题目:http://poj.org/problem?id=2288
题意:给出了n个地点和m座桥(连接顶点的),画出哈密尔顿圈并求出最大值,他们的最大值由三部分决定,1:n个地点的value值之和,2:顶点之间连接之积,3:三个(连续的)顶点之积;要求输出最大值,并且存在最大值的情况总数,同时,对于两个完全逆向的路径可以认为是同一条路径;
分析:发现每个点的状态由前面两个点确定,用DP(S,A,B)表示状态为S时,当前到达A,而上一个点是B时的最大得分,这个状态由DP(S',B,C)通过从B走到A得到,S'=S-(1<<A),即S'状态就是经过B和C但不经过A的一个状态,C是不同于A和B的一个点。
【状态转移】dp[S][A][B] =max(dp[S][A][B],dp[S'][B][C]+temp) 这里的temp指的是加上的得分即Vb*Va+Va,如果构成三角关系(即A和C间有边),temp就要再加上Vb*Va*Vc.
【边界条件】DP((1<<A)+(1<<B),A,B)=Va+Vb+Va*Vb(A和B间有边)表示
参考博客: 点击打开链接#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
ll f[1<<14][14][14],way[1<<14][14][14];
bool edge[14][14];
ll v[14];
int main()
{
int n,m,T;
// freopen("f.txt","r",stdin);
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&v[i]);
if(n==1){
printf("%d 1\n",v[1]);continue;
}
memset(edge,0,sizeof(edge));
int a,b;
while(m--){
scanf("%d%d",&a,&b);
edge[a][b]=edge[b][a]=1;
}
memset(f,-1,sizeof(f));
memset(way,0,sizeof(way));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){ //边界初始化
if(i==j||!edge[i][j])continue;
int ii=1<<(i-1),jj=1<<(j-1);
ll tmp=v[i]+v[j]+v[i]*v[j];
f[ii+jj][i][j]=tmp;
way[ii+jj][i][j]=1;
//cout<<tmp<<endl;
}
}
for(int s=0;s<(1<<n);s++){
for(int i=1;i<=n;i++){
if(!(s&(1<<(i-1))))continue;
for(int j=1;j<=n;j++){
if(!(s&(1<<(j-1)))||i==j||!edge[i][j])continue;
for(int k=1;k<=n;k++){
if(!(s&(1<<(k-1)))||i==k||j==k||!edge[j][k])continue;
int ts=s-(1<<(i-1));
if(f[ts][j][k]==-1)continue;
ll tmp=v[i]+v[i]*v[j]+f[ts][j][k];
if(edge[i][k])tmp+=v[i]*v[j]*v[k]; //如果可以形成三角形
if(f[s][i][j]<tmp){ //如果有更大的值,那么更新,方法数目way也直接由上一条路决定
f[s][i][j]=tmp;
way[s][i][j]=way[ts][j][k];
}
else if(tmp==f[s][i][j])way[s][i][j]+=way[ts][j][k]; //如果相等,way求和
}
}
}
}
ll ans=-1,num=0;
int p=(1<<n)-1;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)continue;
if(ans<f[p][i][j]){
ans=f[p][i][j];num=way[p][i][j];
}
else if(ans==f[p][i][j])num+=way[p][i][j];
}
}
if(ans==-1){
printf("0 0\n");continue;
}
printf("%lld %lld\n",ans,num/2); //因为计算的和f[p][i][j]==f[p][j][i]都加进去了,所以/2
}
return 0;
}