1.每一个点的权值之和
2.对于图中的每一条CiCi+1,加上Vi*Vi+1
3.对于路径中的连续三个点:CiCi+1Ci+2,若在图中,三点构成三角形,则要加上Vi*Vi+1*Vi+2
求一条汉密尔顿路可以获得的最大值,并且还要输出有多少条这样的哈密尔顿路。
分析:取dp[state][i][j]表示state状态下倒数第二个岛为i,最后一个岛为j时的最优解,num[state][i][j]为相应的路径数目,其中state的二进制表示的i位为1表示岛i被访问过,反之为0。
#include <algorithm> #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <vector> #include <queue> #include <cmath> #include <map> #include <set> #define LL long long #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; int val[15]; bool Map[13][13]; int dp[1<<13][13][13]; LL num[1<<13][13][13]; int n,m; int main() { int cas; scanf("%d",&cas); while(cas--){ scanf("%d %d",&n,&m); for(int i=0;i<n;i++) scanf("%d",&val[i]); int u,v; memset(Map,false,sizeof(Map)); while(m--){ scanf("%d %d",&u,&v); u--;v--; Map[u][v]=Map[v][u]=true; } if(n==1){ printf("%d 1\n",val[0]); continue; } memset(dp,-1,sizeof(dp)); memset(num,0,sizeof(num)); for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ if(i!=j&&Map[i][j]){ dp[(1<<i)|(1<<j)][i][j]=val[i]+val[j]+val[i]*val[j]; num[(1<<i)|(1<<j)][i][j]=1; } } } for(int s=0;s<(1<<n);s++){//枚举状态 for(int i=0;i<n;i++){//枚举集合s中倒数第二个点 if(s&(1<<i)){ for(int j=0;j<n;j++){//枚举集合s中的倒数第一个点 if((s&(1<<j))&&(i!=j)&&Map[i][j]&&dp[s][i][j]!=-1){ for(int k=0;k<n;k++){//枚举集合s外的一点 if(i!=k&&j!=k&&Map[j][k]&&(!(s&(1<<k)))){ int tmp=dp[s][i][j]+val[k]+val[j]*val[k]; if(Map[i][k]) tmp+=val[i]*val[j]*val[k]; if(dp[(s|(1<<k))][j][k]<tmp){ dp[(s|(1<<k))][j][k]=tmp; num[(s|(1<<k))][j][k]=num[s][i][j]; } else if(tmp==dp[(s|(1<<k))][j][k]) num[s|(1<<k)][j][k]+=num[s][i][j]; } } } } } } } int ans1=0; LL ans2=0; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ if(i!=j&&Map[i][j]){ if(dp[(1<<n)-1][i][j]>ans1){ ans1=dp[(1<<n)-1][i][j]; ans2=num[(1<<n)-1][i][j]; } else if(ans1==dp[(1<<n)-1][i][j]) ans2+=num[(1<<n)-1][i][j]; } } } cout<<ans1<<' '<<ans2/2<<endl; } return 0; }