题意:
给出一个图,每个点都有一个价值,并且价值的计算方法是这样的:举个例子,如果G是一个未完成的图,u-v是一条边,且u在G中v不在G中,那么现在走到v并且把v加入到G中,于是价值要加上val[v]+val[u]*val[j] u是v的前驱。如果出现u-v ,v-t, t-u 这样的三角环那么价值要多加上val[u]*val[v]*val[t];
题解:
dp[S][i][j]状态为S时上个点走的是i这个点走的是j 的最大价值,way[S][i][j]用来统计方案数。
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
typedef __int64 lld;
#define oo 0x3f3f3f3f
#define Mod 1000000007
#define maxn (1<<13)+1
lld dp[maxn][14][14];
lld way[maxn][14][14];
int val[14],road[14][14];
int main()
{
int n,m,T,u,v;
lld ans,sum;
scanf("%d",&T);
while(T--)
{
memset(road,0,sizeof road);
memset(dp,-1,sizeof dp);
memset(way,0,sizeof way);
scanf("%d %d",&n,&m);
for(int i=0;i<n;i++)
scanf("%d",&val[i]);
for(int i=1;i<=m;i++)
{
scanf("%d %d",&u,&v);
u--;v--;
road[u][v]=road[v][u]=1;
}
int all=(1<<n)-1;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(road[i][j])
{
dp[(1<<i)|(1<<j)][i][j]=val[i]+val[j]+val[i]*val[j];
way[(1<<i)|(1<<j)][i][j]=1;
}
for(int S=0;S<=all;S++)
{
for(int i=0;i<n;i++)
{
if(!(S&(1<<i)))continue;
for(int j=0;j<n;j++)
{
if(!(S&(1<<j)))continue;
if(road[i][j]==0)continue; //printf("状态:%d %d %d dp=%d\n",S,i,j,dp[S][i][j]);
if(dp[S][i][j]==-1)continue;//cout<<"^-^"<<endl;
for(int k=0;k<n;k++)
{
if(S&(1<<k))continue;
if(road[j][k]==0)continue;
int t=val[k]+val[j]*val[k];
if(road[k][i]) t+=val[i]*val[j]*val[k];
int st=S|(1<<k);
if(dp[st][j][k]<dp[S][i][j]+t)
{
dp[st][j][k]=dp[S][i][j]+t;
way[st][j][k]=way[S][i][j];
}
else if(dp[st][j][k]==dp[S][i][j]+t)
way[st][j][k]+=way[S][i][j];
}
}
}
}
ans=sum=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if(dp[all][i][j]>ans)
{
ans=dp[all][i][j];
sum=way[all][i][j];
}
else if(dp[all][i][j]==ans)
sum+=way[all][i][j];
}
if(n==1)
{
ans=val[0];
sum=2;
}
printf("%I64d %I64d\n",ans,sum/2);
}
return 0;
}