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][S] + cost[j][i])

注意给边判重

又用了队列。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define maxn 15
#define INF 0x3f3f3f3f
#define maxs 60000

struct DP {
    int num, state;
}start[maxn];

int n, m;
int cost[maxn][maxn];
int dp[maxn][maxs];
int mod[maxn];

void init() {
    int x, y, z;
    memset(cost, 0x3f, sizeof(cost));
    for(int i = 0; i < m; i++) {
        scanf("%d%d%d", &x, &y, &z);
        cost[x-1][y-1] = cost[y-1][x-1] = min(cost[x-1][y-1], z);
    }
    memset(dp, 0x3f, sizeof(dp));
    for(int i = 0; i < n; i++) {
        dp[i][mod[i]] = 0;
        start[i].num = i;
        start[i].state = mod[i];
    }
}

void solve() {

    queue<DP> q;
    for(int i = 0; i < n; i++)
        q.push(start[i]);
    int ans = INF;
    while(!q.empty()) {
        DP t = q.front();
        q.pop();
        for(int i = 0; i < n; i++) {
            if(i == t.num || cost[i][t.num] == INF)
                continue;
            if(!i && t.state % 3 == 2)
                continue;
            if(i && ( (t.state % mod[i+1]) - (t.state % mod[i]) ) / mod[i] == 2)
                continue;

            if(dp[i][t.state + mod[i]] > dp[t.num][t.state] + cost[t.num][i]) {
                dp[i][t.state + mod[i]] = dp[t.num][t.state] + cost[t.num][i];
                DP tt;
                tt.num = i;
                tt.state = t.state + mod[i];
                q.push(tt);

                bool flag = false;
                int tmp = t.state + mod[i];
                if(dp[i][tmp] < ans) {
                    for(int j = 0; j < n; j++)
                        if(tmp % 3 == 0) {
                            flag = true;
                            break;
                        }
                        else {
                            tmp /= 3;
                        }
                    if(!flag)
                        ans = dp[i][t.state + mod[i]];
                }
            }
        }
    }
    if(ans == INF)
        ans = -1;
    printf("%d\n", ans);
}

void begin() {
    mod[0] = 1;
    for(int i = 1; i < 12; i++)
        mod[i] = mod[i - 1] * 3;
}

int main() {
    begin();
    while(scanf("%d%d", &n, &m) != EOF) {
        init();
        solve();
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-31 02:24:01

HDU - 3001 Travelling (状态压缩)的相关文章

HDU 3001 Travelling 状态压缩dp+3进制

题意:一个人要旅行,他要去n个地方,且这n个地方每个地方最多可以走2次: 给m条路径,寻问最短花费 很明显的状态压缩,但是要求每个点最多只能走两次,就没办法标记当前点走过或是没走过,只能用三进制来表示 1代表地点1被走过一次. 2代表地点1被走过两次. 3(即10)代表地点2被走过一次. 4(即11)代表地点1被走过一次,地点2被走过一次. 5(即12)代表地点1被走过两次,地点2被走过一次. 附AC代码 #include<stdio.h> #include<string.h> i

hdu 3001 Travelling(状态压缩 三进制)

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

HDU 3001【状态压缩DP】

题意: 给n个点m条无向边. 要求每个点最多走两次,要访问所有的点给出要求路线中边的权值总和最小. 思路: 三进制状态压缩DP,0代表走了0次,1,2类推. 第一次弄三进制状态压缩DP,感觉重点是对数据的预处理,利用数组分解各个位数,从而达到类似二进制的目的. 然后就是状态的表示,dp[s][i]表示状态s时到达i的最优值. 状态转移也一目了然,不废话. #include<stdio.h> #include<string.h> #include<algorithm> u

HDU 3001 Travelling 状态DP

TSP问题,不懂就是每个点最多访问两次,最少访问一次. 所以,我们可以用三进制来当做状态. 这个题练习了一下三进制--0.1.2 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #include <string> 8

HDU 3001(状态压缩DP)

题意:遍历所有的城市的最短路径,每个城市最多去两遍.将城市的状态用3进制表示. 状态转移方程为 dp[NewS][i]=min( dp[NewS][i],dp[S][j]+dis[i][j]) S表示遍历点的状态,i表示到达第i个城市. 在到第i个城市的时候看是否存在一个j城市的路径,然后再从j到i更短. #include <algorithm> #include <cstdio> #include <cstring> #define Max 1000001 #defi

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

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

hdu 4568(状态压缩dp)

题意:一张n*m的网格内每个点有话费,还有若干个宝藏,问一个人要走进去拿走所有宝藏在走出来的最小花费. 思路:看宝藏只有13个直接想到了状压dp[i][j]拿了哪几个前一个为j的最小花费,先bfs+优先队列预处理出最短路,然后记忆化搜索就可. 代码如下: 1 /************************************************** 2 * Author : xiaohao Z 3 * Blog : http://www.cnblogs.com/shu-xiaohao

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

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

HDU 3001 Travelling 状压DP

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题意:还是环游地图的问题,只不过这回旅行者对自己有着严格的要求,地图上每个点的经过次数不能超过两次. 思路:依然是状压DP问题,根上一道很像,只不过这次对于每个点来说有三种状态,分别是未经过,经过一次,经过两次.所以要用三进制的数来进行状态压缩,这个关键点想明白了其他的和上一道基本一样了.对于我来说需要注意的是:能够到达某一个点经过了两次的状态的前一个状态是这个点已经经过了一次的状态,而不是从来未

hdu 3001 Travelling TSP变形 三进制状压dp

// hdu 3001 TSP问题的变形 // 这次到每个点最多两次,所以可以用三进制的类推 // dp[S][u]表示当前在u点访问状态为S时所得到的最小的开销 // 采用刷表法,即用当前的状态推出它所能转移的状态 // dp[S][u] 可以到达的状态为dp[S+state[v]][v](dist[u][v]!=inf) // dp[S+state[v]][v] = max(dp[S+state[v]][v],dp[S][u]+dist[u][v]); // 其中每个点最多访问2次 // 技