题意:有N个点,M边条,找到一条哈密尔顿路,求最后的最大值及该值有多少条路径
第个点的值V[i],路径的值有三个来源
1、路中所有点的值相加
2、路中每两个相邻两点的积v[i]*v[j]
3、路中相隔一点的两点之间存在在路径则相加这三点的积
方法:dp[S][i][j]: S为状态,i为上一个选取点的位置,j为当前选点位置。
S中的每个二进制位1表示该点已经路过,否则没有
其中存最大值,
num[S][i][j]: 状态同上,其中存到达该状态最大值的数目。
网址:http://poj.org/problem?id=2288
#include<iostream>
using namespace std;
int n,m;
bool map[13][13];
int dp[1<<13][13][13];
int num[1<<13][13][13];
int v[13];
int main()
{
freopen("in","r",stdin);
int i,j,k,t,cur;
int c;
cin>>c;
while (c--)
{
cin>>n>>m;
for (i=0;i<n;i++)
scanf("%d",v+i);
memset(map,false,sizeof(map));
while (m--)
scanf("%d%d",&i,&j),i--,j--,map[i][j]=map[j][i]=true;
if (n==1) //点数为1时的特殊处理
{
cout<<v[0]<<' '<<1<<endl;
continue;
}
int full=(1<<n)-1;
for (i=0;i<=full;i++) //初始化
for (j=0;j<n;j++)
for (k=0;k<n;k++)
dp[i][j][k]=num[i][j][k]=-1;
for (i=0;i<n;i++) //初始化第一个条件
for (j=0;j<n;j++) if (i!=j && map[i][j])
dp[(1<<i)|(1<<j)][i][j]=v[i]+v[j]+v[i]*v[j],num[(1<<j)|(1<<i)][i][j]=1;
for (i=0;i<=full;i++) //对第一个状态逐个计算
for (j=0;j<n;j++) if (i&(1<<j))
for (k=0;k<n;k++) if (dp[i][j][k]!=-1)
for (t=0;t<n;t++) if (!((1<<t)&i) && map[k][t])
{
cur=dp[i][j][k]+v[t]+v[k]*v[t];
if (map[j][t])
cur+=v[j]*v[k]*v[t];
if (cur>dp[i|(1<<t)][k][t])
dp[i|(1<<t)][k][t]=cur,num[i|(1<<t)][k][t]=num[i][j][k];
else if (cur==dp[i|(1<<t)][k][t])
num[i|(1<<t)][k][t]+=num[i][j][k];
}
int big=-1;
for (i=0;i<n;i++)
for (j=0;j<n;j++)
big=max(big,dp[full][i][j]);
if (big==-1) //全连通的路径不存在
{
cout<<"0 0"<<endl;
continue;
}
long long sum=0;
for (i=0;i<n;i++) //计算总条件。
for (j=0;j<n;j++) if (dp[full][i][j] == big)
sum+=num[full][i][j];
cout<<big<<' '<<sum/2<<endl;
}
return 0;
}