hdu-3001 三进制状态压缩+dp

用dp来求最短路,虽然效率低,但是状态的概念方便解决最短路问题中的很多限制,也便于压缩以保存更多信息。

本题要求访问全图,且每个节点不能访问两次以上。所以用一个三进制数保存全图的访问状态(3^10,空间是足够的),用dp[z+bit[j]][j]=dp[z][i]+ct[i][j]就可以表示,从上一状态以i为结束点,转移到把j加入路径末端后的状态(感叹一下位运算的神奇)。

//
//  main.cpp
//  hdu_3001
//
//  Created by Luke on 2016/11/12.
//  Copyright ? 2016年 Luke. All rights reserved.
//

#include <iostream>
#include <cmath>
#include <algorithm>

#include <cstdio>
#define N 15
#define zip 70000
#define INF 919900000//原来要开这么大哇
using namespace std;
int n,m;
int ct[N][N];//存边权
int dp[zip][N];//z状态下,以j为终点的路径费用
int bit[20];
void addE(int from,int to,int fee);
void ini();
int digit(int num,int pos);//返回压缩后的当前位置状态
int solve()
{
    int ans=INF;
    for(int z=0;z<bit[n];z++)
    {
        int f=1;
        for(int j=0;j<n;j++)//表示以j结尾,从位置i转移过来
        {
            int fix=digit(z,j);
            if(fix==2) continue;
            if(fix==0) f=0;
            //if(dp[z][j]==INF) continue;
            for(int i=0;i<n&&z+bit[j]<bit[n];i++)
                dp[z+bit[j]][j]=min(dp[z+bit[j]][j],dp[z][i]+ct[i][j]);
        }
        if(f)//如果是合法状态,就更新一遍ans
            for(int i=0;i<n;i++)
                ans=min(ans,dp[z][i]);
    }
    if(ans==INF)
        return -1;
    return ans;
}
int main(int argc, const char * argv[]) {
    cin.sync_with_stdio(false);
    bit[0]=1;
    for(int i=1;i<=15;i++)
        bit[i]=bit[i-1]*3;
    while(cin>>n>>m)
    {
        int a,b,c;
        ini();

        for(int i=0;i<m;i++)
            cin>>a>>b>>c,addE(a,b,c);
        cout<<solve()<<endl;
    }

    return 0;
}
void addE(int from,int to,int fee)
{
    from--,to--;//为了节约空间,节点从0开始计数
    ct[from][to]=ct[to][from]=min(ct[to][from],fee);
}
void ini()
{
    for(int i=0;i<N;i++)
        for(int j=0;j<N;j++)
            ct[i][j]=INF;
    for(int i=0;i<zip;i++)
        for(int j=0;j<N;j++)
        {
            if(bit[j]==i)
                dp[i][j]=0;
            else
                dp[i][j]=INF;
        }
}
int digit(int num,int pos)
{
    for(int i=0;i<pos;i++)
        num/=3;
    return num%3;
}
时间: 2024-11-05 02:32:30

hdu-3001 三进制状态压缩+dp的相关文章

HDU 3001 Travelling (三进制状态压缩 DP)

题意:有 n 个city,可以选择任一城市作为起点,每个城市不能访问超过2次, 城市之间有权值,问访问全部n个城市需要的最小权值. 思路:因为每个城市可以访问最多两次,所以用三进制表示访问的状态. 详细见代码注释!!!! #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #include<cmath> #inclu

HDU 3001 Travelling(状态压缩DP+三进制)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题目大意:有n个城市,m条路,每条路都有一定的花费,可以从任意城市出发,每个城市不能经过两次以上,要求经过所有城市并且花费最少,求出最小花费. 解题思路:三进制的状态压缩DP,跟二进制还是有一点不一样的,因为三进制没有直接的位运算,还要自己先做处理利用num[i][j]记录数字i各位的三进制表示方便计算,其他的就跟二进制状态压缩没有太大区别了.还有注意: ①开始要将n个起点初始化,dp[bit

hdu3001 (三进制状态压缩 dp)

src: http://acm.hdu.edu.cn/showproblem.php?pid=3001 思路:每个顶点经过最多2次,也就是有0 1 2三种状态!用bit[]存三进制下各位的值(这样dp的状态概念就可以解决最短路问题的许多限制,通过压缩可以保存更多的值~),dp[z][j]表示z状态下,以j为终点的路径费用!!! 待更~~~ 原文地址:https://www.cnblogs.com/WindFreedom/p/8763093.html

HDU 3001 三进制状压DP

N个城市,M条道路,每条道路有其经过的代价,每一个城市最多能够到达两次,求走全然部城市最小代价,起点随意. 三进制状压.存储每一个状态下每一个城市经过的次数. 转移方程: dp[i+b[k]][k]=Min(dp[i+b[k]][k],dp[i][j]+dis[j][k]); #include "stdio.h" #include "string.h" const int inf=0x3f3f3f3f; int b[15],mark[60010][15],dp[60

HDU 3001 三进制 状压dp

Travelling Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3789    Accepted Submission(s): 1182 Problem Description After coding so many days,Mr Acmer wants to have a good rest.So travelling is

hdu 3217 Health(状态压缩DP)

Health Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 527    Accepted Submission(s): 145 Problem Description Unfortunately YY gets ill, but he does not want to go to hospital. His girlfriend LM

hdu 4057 AC自动机+状态压缩dp

http://acm.hdu.edu.cn/showproblem.php?pid=4057 Problem Description Dr. X is a biologist, who likes rabbits very much and can do everything for them. 2012 is coming, and Dr. X wants to take some rabbits to Noah's Ark, or there are no rabbits any more.

HDU 4511 (AC自动机+状态压缩DP)

题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4511 题目大意:从1走到N,中间可以选择性经过某些点,比如1->N,或1->2->N,但是某些段路径(注意不是某些条)是被禁止的.问从1->N的最短距离. 解题思路: AC自动机部分: 如果只是禁掉某些边,最短路算法加提前标记被禁的边即可. 但是本题是禁掉指定的路段,所以得边走边禁,需要一个在线算法. 所以使用AC自动机来压缩路段,如禁掉的路段是1->2->3,那么in

HDU - 3001 Travelling (状态压缩)

题目大意:有一个人要去旅游,他想要逛遍所有的城市,但是同一个城市又不想逛超过2次.现在给出城市之间的来往路费,他可以选择任意一个点为起点.问逛遍所有城市的最低路费是多少 解题思路:这题和POJ - 3311 Hie with the Pie相似 这里的状态标记要用三进制数来表示,就可以表示每个城市去过的次数了 设dp[i][state]为现在在i城市,逛过的城市状态为state的最低路费 状态转移方程: dp[i][S + i城市标记] = min(dp[i][S + i城市标记], dp[j]