给你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 }

 

posted on 2018-04-26 16:55  chagin  阅读(139)  评论(0)    收藏  举报