題目大意:求一條哈密頓迴路,但是權值計算不同,包括三部分: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;
}