hdu3001 Travelling 旅行商问题 状态压缩DP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001

Travelling

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4642    Accepted Submission(s): 1531

Problem Description

After coding so many days,Mr Acmer wants to have a good rest.So travelling is the best choice!He has decided to visit n cities(he insists on seeing all the cities!And he does not mind which city being his start station because superman can bring him to any city at first but only once.), and of course there are m roads here,following a fee as usual.But Mr Acmer gets bored so easily that he doesn‘t want to visit a city more than twice!And he is so mean that he wants to minimize the total fee!He is lazy you see.So he turns to you for help.

Input

There are several test cases,the first line is two intergers n(1<=n<=10) and m,which means he needs to visit n cities and there are m roads he can choose,then m lines follow,each line will include three intergers a,b and c(1<=a,b<=n),means there is a road between a and b and the cost is of course c.Input to the End Of File.

Output

Output the minimum fee that he should pay,or -1 if he can‘t find such a route.

Sample Input

2 1

1 2 100

3 2

1 2 40

2 3

50

3 3

1 2 3

1 3 4

2 3 10

Sample Output

100

90

7

题意:还是旅行商问题。这个人要去旅行放松,去n个城市,从哪里出发都可以,但是每个地方最多经过两次,求经过每个点的路线的最小花费。如果不行,则输出-1.

分析:还是用dp[i][j]来表示状态为i的时,终点为j时候的最小花费。

因为题目中说最多经过两次,所以用三进制来表示,这样每一位如果没有经过的时候就为0,经过一次就为1,经过两次就为2.

最后的答案就是dp[sta][j]中的最小值,其中sta为每个位上的数字至少为1的所有状态。j为1~n.

要注意一下有可能会有重边,在初始化地图的时候,需要更新a点到b点的最小花费,因为这个错了好几次。

三进制判断的时候写的有点搓,时间还是比较长。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <string>
 5 #include <cmath>
 6 #include <vector>
 7 #include <algorithm>
 8 using namespace std;
 9 #define INF 0x3f3f3f
10 int n, m;
11 int mp[11][11], dp[60000][11];
12 int fun(int pos){
13     return int(pow(3.0, pos));
14 }
15 int main(){
16     while(scanf("%d%d", &n, &m) != EOF){
17         int a, b, c;
18         for(int i = 1; i <= n; i++){
19             for(int j = 1; j <= n; j++){
20                 if(i == j) mp[i][j] = 0;
21                 else mp[i][j] = -1;
22             }
23         }
24         for(int i = 1; i <= m; i++){
25             scanf("%d%d%d", &a, &b, &c); //注意重边。
26             if(mp[a][b] == -1) mp[a][b] = mp[b][a] = c;
27             else mp[a][b] = mp[b][a] = min(mp[a][b], c);
28         }
29         for(int i = 0; i < (fun(n)); i++){
30             for(int j = 1; j <= n; j++) dp[i][j] = -1;
31         }
32         for(int pos = 1; pos <= n; pos++) dp[fun(pos-1)][pos] = 0;
33
34         for(int i = 0; i < (fun(n)); i++){
35             for(int j = 1; j <= n; j++){
36                 if(dp[i][j] == -1) continue;
37                 for(int k = 1; k <= n; k++){
38                     if(mp[j][k] == -1) continue; //如果不连通
39                     int tpos = i;
40                     for(int ii = 1; ii < k; ii++) tpos /= 3;
41                     tpos = tpos%3; //找到那一位。
42                     if(tpos == 2) continue;  //这个点已经走了两次了,不能再经过了
43                     if(dp[i+fun(k-1)][k] == -1) dp[i+fun(k-1)][k] = dp[i][j] + mp[j][k];
44                     if(dp[i+fun(k-1)][k] >= dp[i][j] + mp[j][k]) dp[i+fun(k-1)][k] = dp[i][j] + mp[j][k];
45                 }
46             }
47         }
48         int sum = 0;
49         for(int i = 0; i < n; i++) sum += int(pow(3.0, i));
50         int Min = INF;
51         //sum是每个位上正好为1的状态,从sum开始循环。
52         for(int i = sum; i < fun(n); i++){
53             for(int j = 1; j <= n; j++){
54                  bool flag = true;
55                 int temp = i, r;
56                 while(temp){
57                     r = temp%3;
58                     if(r == 0){
59                         flag = false; break;
60                     }
61                     temp /= 3;
62                 }
63                 if(flag == false) continue; //判断是否有位上为0,这样的状态是不满足条件的。
64                 if(dp[i][j] <= Min && dp[i][j] != -1) Min = dp[i][j];
65             }
66         }
67         printf("%d\n",Min == INF?-1:Min);
68     }
69     return 0;
70 }
时间: 2024-10-17 03:43:59

hdu3001 Travelling 旅行商问题 状态压缩DP的相关文章

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 三进制状态压缩+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

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

编程题-旅行商问题-状态压缩DP

题目 给定一个n个顶点组成的带权有向图的距离矩阵d(n,n),要求从顶点0出发,经过每个顶点恰好一次后再回到顶点0,怎么样使得经过的变的总权重最小值 分析 因为所有可能的路线有(n-1)!种,可以通过DP来解决 一说到DP,第一步也是最重要的一步是写出递归表达式.假设已经访问过的顶点的集合为S,当前所在的顶点为v.用dp[S][v]表示从v出发访问剩余所有顶点,最终回到顶点0的路径的权重和的最小值. dp[V][0]=0 dp[S][v]=min(dp[S∪u][u]+d(v,u)|u∈S) 但

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

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

HDU3768 Shopping(状态压缩DP+spfa)旅行商问题

Shopping Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 577    Accepted Submission(s): 197 Problem Description You have just moved into a new apartment and have a long list of items you need

hdu3001Travelling (状态压缩DP,三进制)

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

POJ 3254 Corn Fields 状态压缩DP (C++/Java)

http://poj.org/problem?id=3254 题目大意: 一个农民有n行m列的地方,每个格子用1代表可以种草地,而0不可以.放牛只能在有草地的,但是相邻的草地不能同时放牛, 问总共有多少种方法. 思路: 状态压缩的DP. 可以用二进制数字来表示放牧情况并判断该状态是否满足条件. 这题的限制条件有两个: 1.草地限制. 2.相邻限制. 对于草地限制,因为输入的时候1是可以种草地的. 以"11110"草地分析,就只有最后一个是不可以种草的.取反后得00001  .(为啥取反

HDU1565(状态压缩dp)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8170    Accepted Submission(s): 3095 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数