POJ 2288 汉密尔顿回路 DP解决

题目大意:

有n个岛屿,令Vi为岛屿Ci的权值。一条汉密尔顿路径C1,C2,C3...Cn的值为3部分

第一部分,将路径中的岛的权值相加,第二部分将每条边上的(Ci,Cj),加上所有的Vi*Vj

第三部分,如果连续经过的3个城市可以形成3角联通,那么加上Vi*Vj*Vk

求出一条路径使其权值最大,并记录有多少可以达到最大权值的路径

1->2->3 , 3->2->1 视为相同路径

这里最多13个城市,所以用2进制表示是否到达当前位置的城市

这里用dp[i][k][j] 表示到达i状态时,最后到达的两个城市为j,k,这样可以达到的最大权值

dp[i|(1<<(t-1)][j][t] = max{dp[i|(1<<(t-1)][j][t] , dp[i][k][j]+val[t]+val[j]*val[t]+ edge[k][t]?val[j]*val[k]*val[t]:0}

注意每次更新dp值同时记录一个到达当前状态的路径数量cnt[i][k][j]

这里要注意只有一个城市的时候要特判

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <cmath>
 5 using namespace std;
 6 #define N 14
 7 #define ll long long
 8 int n,m;
 9 ll dp[1<<N][N][N] , val[N] , cnt[1<<N][N][N];//cnt记录当前状态下可行的方法总数
10 bool edge[N][N];
11 
12 void getDp()
13 {
14     memset(cnt , 0 ,sizeof(cnt));
15     memset(dp , -1 , sizeof(dp));
16     int all = (1<<n);
17     dp[0][0][0]=0 , cnt[0][0][0]=0;
18     for(int i=1 ; i<=n ; i++) dp[1<<(i-1)][0][i]=val[i],cnt[1<<(i-1)][0][i]=1;
19     for(int i=1 ; i<all ; i++){
20         for(int j=1 ; j<=n ; j++){
21             if(!(i&(1<<(j-1)))) continue;
22             for(int k=0 ; k<=n ; k++){
23                 if(k == 0 && (i!=(1<<(j-1)))) continue;
24                 if(k==j || (!(i&(1<<(k-1))) && k!=0)) continue;
25                 if(dp[i][k][j]<0) continue;
26 
27                 for(int t=1 ; t<=n ; t++){
28                     if(!edge[j][t] || i&(1<<(t-1))) continue;
29                     ll v = dp[i][k][j]+val[t]+val[t]*val[j];
30                     if(edge[t][k]) v = v+val[j]*val[k]*val[t];
31                     int status = i|(1<<(t-1));
32                     if(dp[status][j][t]<0 || dp[status][j][t]<v){
33                         dp[status][j][t]=v;
34                         cnt[status][j][t]=cnt[i][k][j];
35                     }
36                     else if(dp[status][j][t] == v){
37                         cnt[status][j][t]+=cnt[i][k][j];
38                     }
39                                         //debug
40                  //   print(status);cout<<endl;
41                    // cout<<i<<" "<<j<<" "<<k<<" "<<dp[status][k][t]<<endl;
42                 }
43             }
44         }
45     }
46 }
47 
48 int main()
49 {
50    // freopen("a.in" , "r" , stdin);
51     int T;
52     scanf("%d" , &T);
53     while(T--)
54     {
55         scanf("%d%d" , &n , &m);
56         for(int i=1 ; i<=n ; i++) scanf("%I64d" , val+i);
57         memset(edge , 0 , sizeof(edge));
58         int a,b;
59         for(int i=0 ; i<m ; i++){
60             scanf("%d%d" , &a , &b);
61             edge[a][b]=true;
62             edge[b][a]=true;
63         }
64         getDp();
65         int all=(1<<n);
66         ll maxn = -1 , ans=0;
67         for(int i=0 ; i<=n ; i++)
68             for(int j=0 ; j<=n ; j++)
69             {
70                 maxn=max(maxn,dp[all-1][i][j]);
71             }
72         if(maxn == -1){
73             puts("0 0");
74             continue;
75         }
76         for(int i=0 ; i<=n ; i++)
77             for(int j=0 ; j<=n ; j++)
78                 if(maxn == dp[all-1][i][j]) ans+=cnt[all-1][i][j];
79         /***要注意只有一个城市的情况下要特判***/
80         printf("%I64d %I64d
" , maxn , ans/2?ans/2:1);
81     }
82     return 0;
83 }
原文地址:https://www.cnblogs.com/CSU3901130321/p/4468620.html