求一个图的哈密顿路径的最大权及其路径数。显然状态压缩+DP。
dp[v][u][S] 表示从v走到当前顶点 u且走过的顶点集合是S的 最大权值和方案数
这题我用记忆化搜索,从终点开始递归进行,感觉这样比较容易转移。
就是搜索一个状态可以从哪些状态转移过来,顺便统计方案数。搜索时要注意一些细节,转移要合法还有可能某个状态是无解的要跳过。
还有一些细节什么什么的。。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 bool G[13][13]; 6 int n,val[13]; 7 __int64 d[13][13][1<<13],cnt[13][13][1<<13]; 8 __int64 dfs(int u1,int u2,int S){ 9 if(d[u1][u2][S]!=-1) return d[u1][u2][S]; 10 int res=0; 11 for(int u0=0; u0<n; ++u0){ 12 if(u0==u1 || u0==u2 || !G[u0][u1] || ((S>>u0)&1)==0) continue; 13 if(dfs(u0,u1,S^(1<<u2))==0) continue; 14 int tmp=dfs(u0,u1,S^(1<<u2))+val[u1]*val[u2]; 15 if(G[u0][u2]) tmp+=val[u0]*val[u1]*val[u2]; 16 res=max(res,tmp); 17 } 18 for(int u0=0; u0<n; ++u0){ 19 if(u0==u1 || u0==u2 || !G[u0][u1] || ((S>>u0)&1)==0) continue; 20 if(dfs(u0,u1,S^(1<<u2))==0) continue; 21 int tmp=dfs(u0,u1,S^(1<<u2))+val[u1]*val[u2]; 22 if(G[u0][u2]) tmp+=val[u0]*val[u1]*val[u2]; 23 if(res==tmp) cnt[u1][u2][S]+=cnt[u0][u1][S^(1<<u2)]; 24 } 25 return d[u1][u2][S]=res; 26 } 27 int main(){ 28 int t,m,a,b; 29 scanf("%d",&t); 30 while(t--){ 31 memset(d,-1,sizeof(d)); 32 memset(cnt,0,sizeof(cnt)); 33 memset(G,0,sizeof(G)); 34 scanf("%d%d",&n,&m); 35 int sum=0; 36 for(int i=0;i<n;++i) scanf("%d",val+i),sum+=val[i]; 37 while(m--){ 38 scanf("%d%d",&a,&b); 39 --a; --b; 40 G[a][b]=G[b][a]=1; 41 } 42 if(n==1){ 43 printf("%d %d ",val[0],1); 44 continue; 45 } 46 for(int i=0; i<n; ++i){ 47 for(int j=0; j<n; ++j){ 48 if(i==j || !G[i][j]) continue; 49 d[i][j][(1<<i)|(1<<j)]=val[i]*val[j]; 50 cnt[i][j][(1<<i)|(1<<j)]=1; 51 } 52 } 53 __int64 res=0,num=0; 54 for(int i=0; i<n; ++i){ 55 for(int j=0; j<n; ++j){ 56 if(i==j || !G[i][j]) continue; 57 res=max(res,dfs(i,j,(1<<n)-1)); 58 } 59 } 60 for(int i=0; i<n; ++i){ 61 for(int j=0; j<n; ++j){ 62 if(i==j || !G[i][j]) continue; 63 if(res==dfs(i,j,(1<<n)-1)) num+=cnt[i][j][(1<<n)-1]; 64 } 65 } 66 if(res) res+=sum; 67 printf("%I64d %I64d ",res,num>>1); 68 } 69 return 0; 70 }