HDU 3001 Travelling:TSP(旅行商)【节点最多经过2次】
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001
题意:
有n个城市,m条双向道路,每条道路走一次需要花费路费v。你可以将任意一个城市作为起点出发,然后遍历每一个城市,并保证同一个城市最多经过2次。问你遍历这些城市的最小费用是多少。
题解:
传统的TSP问题中,每个城市只能经过一次,做法为三重for循环,分别枚举城市的state、现在所处位置i、下一步要到达的城市j。
核心Code:
1 memset(dp,-1,sizeof(dp));
2 dp[1<<start][start]=0;
3 for(int state=0;state<(1<<n);state++)
4 {
5 for(int i=0;i<n;i++)
6 {
7 if(dp[state][i]!=-1)
8 {
9 for(int j=0;j<n;j++)
10 {
11 if(i!=j && !((state>>j)&1))
12 {
13 if(dp[state|(1<<j)][j]==-1 || dp[state|(1<<j)][j]>dp[state][i]+dis[i][j])
14 {
15 dp[state|(1<<j)][j]=dp[state][i]+dis[i][j];
16 }
17 }
18 }
19 }
20 }
21 }
在这道题中,与传统TSP的唯一区别是每个城市最多经过的次数由1次变为了2次。那么表示每座城市的状态state也应该相应改为用三进制数表示,每一位上的数字代表对应城市已经经过的次数。
所以把所有的二进制改为三进制就好啦 ( ̄▽ ̄)~*
注:不用对于每一个起点分别求一次dp,会T。。。在开始要把所有的dp[update(0, i)][i] = 0
AC Code:
1 #include <iostream>
2 #include <stdio.h>
3 #include <string.h>
4 #include <queue>
5 #define MAX_N 15
6 #define MAX_S 60000
7 #define INF 100000000
8
9 using namespace std;
10
11 const int POW[]={1,3,9,27,81,243,729,2187,6561,19683,59049,177147,531441,1594323,4782969};
12
13 int n,m;
14 int a,b,v;
15 int ans;
16 int dis[MAX_N][MAX_N];
17 int dp[MAX_S][MAX_N];
18
19 void init()
20 {
21 for(int i=0;i<n;i++)
22 {
23 for(int j=0;j<n;j++)
24 {
25 dis[i][j]=INF;
26 if(i==j) dis[i][j]=0;
27 }
28 }
29 }
30
31 void read()
32 {
33 for(int i=0;i<m;i++)
34 {
35 cin>>a>>b>>v;
36 dis[a-1][b-1]=min(dis[a-1][b-1],v);
37 dis[b-1][a-1]=min(dis[b-1][a-1],v);
38 }
39 }
40
41 int query(int a,int k)
42 {
43 return a/POW[k]%3;
44 }
45
46 int update(int a,int k)
47 {
48 return a+POW[k];
49 }
50
51 bool check(int state)
52 {
53 for(int i=0;i<n;i++)
54 {
55 if(query(state,i)==0) return false;
56 }
57 return true;
58 }
59
60 void solve()
61 {
62 ans=INF;
63 memset(dp,-1,sizeof(dp));
64 for(int i=0;i<n;i++)
65 {
66 dp[update(0,i)][i]=0;
67 }
68 for(int state=0;state<POW[n];state++)
69 {
70 for(int i=0;i<n;i++)
71 {
72 if(dp[state][i]!=-1)
73 {
74 for(int j=0;j<n;j++)
75 {
76 if(i!=j && query(state,j)<2)
77 {
78 int nex=update(state,j);
79 if(dp[nex][j]==-1 || dp[nex][j]>dp[state][i]+dis[i][j])
80 {
81 dp[nex][j]=dp[state][i]+dis[i][j];
82 }
83 }
84 }
85 if(check(state)) ans=min(ans,dp[state][i]);
86 }
87 }
88 }
89 }
90
91 void print()
92 {
93 if(ans==INF) cout<<-1<<endl;
94 else cout<<ans<<endl;
95 }
96
97 int main()
98 {
99 while(cin>>n>>m)
100 {
101 init();
102 read();
103 solve();
104 print();
105 }
106 }