给你n个点和m条边,每个节点有一个权值,告诉你哪些边相连。一条哈密顿回路上的值是这路上的点权值相加,和相邻点相乘的和,如果有环还要加上乘积。即v[i1]+...+v[in]+v[i1]*v[i2]+...+v[in-1]*v[in]+v[i]*v[j]*v[k]+...。
这是一道状态压缩dp的问题,如果只考虑二维即走过的点和目前的点,就很难算出环部分的值。那么可以再加一维增加一个点表示走过的路上的任意一个点。
f[i][j][s]表示目前在j,走过的路状态为s,i是其中一个点。
考虑加入一个点k,那么k是不存在s中的,新状态为 s|(1<<k),权值会增加v[k]+v[j]*v[k]。如果i和k相连,那么还要加上v[i]*v[j]*v[k]。
如果加入k会比没加的权值更大就更新,注意此题还要算有多少条路径,所以每次更新要考虑路径可以多少条。初始化是1条。
代码如下:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 typedef long long ll; 6 int q,n,m,v[23],x,y; 7 int mp[14][14]; 8 ll f[14][14][1<<14],way[14][14][1<<14],road,ans; 9 void init() 10 { 11 memset(mp,0,sizeof mp); 12 memset(way,0,sizeof way); 13 } 14 void dfs() 15 { 16 memset(f,-1,sizeof f); 17 for(int i=0;i<n;++i) 18 for(int j=0;j<n;++j) 19 if(mp[i][j]) 20 f[i][j][(1<<i)|(1<<j)]=v[i]+v[j]+v[i]*v[j], 21 way[i][j][(1<<i)|(1<<j)]=1; 22 23 for(int s=3;s<1<<n;++s){ 24 for(int i=0;i<n;++i)if(s>>i&1){ 25 for(int j=0;j<n;++j){ 26 if(i==j||!(s&1<<j)||f[i][j][s]==-1) 27 continue; 28 29 for(int k=0;k<n;++k)if(!(s>>k&1)){ 30 if(!mp[j][k]) 31 continue; 32 ll tmp=0; 33 int ns=s|(1<<k); 34 if(mp[k][i]) 35 tmp=f[i][j][s]+v[k]+v[j]*v[k]+v[i]*v[j]*v[k]; 36 else tmp=f[i][j][s]+v[k]+v[j]*v[k]; 37 if(tmp>f[j][k][ns]) 38 f[j][k][ns]=tmp,way[j][k][ns]=way[i][j][s]; 39 else if(tmp==f[j][k][ns]) 40 way[j][k][ns]+=way[i][j][s]; 41 } 42 } 43 } 44 } 45 46 road=0; 47 ans=-1; 48 for(int i=0;i<n;++i) 49 for(int j=0;j<n;++j) 50 if(i!=j){ 51 if(f[i][j][(1<<n)-1]>ans){ 52 ans=f[i][j][(1<<n)-1]; 53 road=way[i][j][(1<<n)-1]; 54 } else if(ans==f[i][j][(1<<n)-1]) 55 road+=way[i][j][(1<<n)-1]; 56 } 57 } 58 int main(int argc, char **argv) { 59 cin>>q; 60 while(q--){ 61 init(); 62 cin>>n>>m; 63 for(int i=1;i<=n;++i) 64 cin>>v[i-1]; 65 for(int i=1;i<=m;++i){ 66 cin>>x>>y; 67 mp[x-1][y-1]=mp[y-1][x-1]=1; 68 } 69 if(n==1){ 70 cout<<v[0]<<" 1"<<endl; 71 continue; 72 } 73 dfs(); 74 if(ans==-1) 75 cout<<"0 "<<0<<endl; 76 else cout<<ans <<' '<<road/2<<endl; 77 } 78 return 0; 79 }
浙公网安备 33010602011771号