题目大意:求一条哈密顿回路,但是权值计算不同,包括三部分:1.经过的所有点的权值相加。2.经过的连续两个点的权值的乘积。3.能够构成三角型的连续三个点的乘积。这些全部加起来就是这条回路的总权值。输出最大权值和这个最大权值的路线有多少条
解题思路:先处理好两相连的情况,如果i与j,我们很容易得到dp[i][j][s]=(v[i]+v[j]+v[i]*v[j]);这相当于dp的初始化,i与j表 示相连的两点,s表示当前走过的状态,接下来就是处理三点之间的关系了,当i与j满足相连关系时,枚举第 三个点的所有情况,当他满足与j相连是,增加量ans=v[k]*v[j]+v[k], 若果k还满足了与i相连,那么 ans=ans+v[i]*v[j]*v[k];由于此题还要记录这样的路线数量,因此我们还需要一的三维数组记录到达各个路线的条数
当满足相等的情况是,num数组就应该相加进行更新,当新的路线权值大于旧的路线是,我们只需覆盖跟新,(想想为什么)(注意转移时的各种满足条件,不要漏写!!!)
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL __int64
LL dp[15][15][1<<13],num[15][15][1<<13];
int map[13][13],a1[15],v[15];
int main()
{
int T,n,m;
scanf("%d",&T);
while(T--)
{
int i,j,k,s,a,b;
memset(map,0,sizeof(map));
memset(num,0,sizeof(num));
memset(dp,0,sizeof(dp));
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
{
scanf("%d",&v[i]);
}
for(i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
a--,b--;
map[a][b]=map[b][a]=1;
}
a1[0]=1;
for(i=1;i<=13;i++)
{
a1[i]=a1[i-1]*2;
}
if(n==1)//只有一个点时,直接输出第一个点的点权
{
printf("%d 1\n",v[0]);
}
else
{
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(map[i][j]==0||i==j)continue;
int s=(a1[i]|a1[j]);
dp[i][j][s]=(v[i]+v[j]+v[i]*v[j]);
num[i][j][s]=1;//记录满足条件的路径有几条
}
}
for(s=0;s<a1[n];s++)
{
for(i=0;i<n;i++)
{
if((s&a1[i])==0)continue;
for(j=0;j<n;j++)
{
if(i==j||(s&a1[j])==0||dp[i][j][s]==0)continue;
if(map[i][j]==0)continue;
for(k=0;k<n;k++)
{
if(i==k||j==k||(s&a1[k])!=0||map[k][i]==0)continue;
int t=s|a1[k];
LL ans1=v[i]*v[k]+v[k];//k与i相连
if(map[k][j]!=0)//k与j相连满足,那么i,j,k三点两两相连
{
ans1+=v[i]*v[j]*v[k];
}
if(dp[k][i][t]<dp[i][j][s]+ans1)
{
dp[k][i][t]=dp[i][j][s]+ans1;
num[k][i][t]=num[i][j][s];
}
else if(dp[k][i][t]==dp[i][j][s]+ans1)
{
dp[k][i][t]=dp[i][j][s]+ans1;
num[k][i][t]+=num[i][j][s];
}
}
}
}
}
LL ans=0,tol=0;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(ans<dp[i][j][a1[n]-1])
{
ans=dp[i][j][a1[n]-1];
tol=num[i][j][a1[n]-1];
}
else if(ans==dp[i][j][a1[n]-1])
{
ans=dp[i][j][a1[n]-1];
tol+=num[i][j][a1[n]-1];
}
}
}
printf("%I64d %I64d\n",ans,tol/2);//除以2的原因是因为无向图,而i到j,j到i我们各算了一次
}
}
return 0;
}