状压DP。 f[i][j][k]表示走的点的状态是i,倒数第二个岛是j,最后一个是k的mincost,cnt表示该状态下的方案数。统计方案数就和23号的考试题一个套路。 注意加个特判,判1个点的状态。
状压DP。
f[i][j][k]表示走的点的状态是i,倒数第二个岛是j,最后一个是k的mincost,cnt表示该状态下的方案数。统计方案数就和23号的考试题一个套路。
注意加个特判,判1个点的状态。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int n,m,f[1<<14][14][14],g[14][14],val[14],T; long long cnt[1<<14][14][14]; int main() { scanf("%d",&T); while(T--) { memset(f,-1,sizeof f); memset(g,0,sizeof g); memset(cnt,0,sizeof cnt); scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%d",&val[i]); for(int i=1,u,v;i<=m;i++) { scanf("%d%d",&u,&v);u--,v--; g[u][v]=g[v][u]=1;f[(1<<u)|(1<<v)][u][v]=f[(1<<u)|(1<<v)][v][u]=val[u]+val[v]+val[u]*val[v],cnt[(1<<u)|(1<<v)][u][v]=cnt[(1<<u)|(1<<v)][v][u]=1; } if(n==1){printf("%d 1\n",val[0]);continue;} for(int i=0;i<1<<n;i++) { for(int j=0;j<n;j++) for(int k=0;k<n;k++) if(g[j][k]&&(i&(1<<j))&&~f[i][j][k]) for(int l=0;l<n;l++) { if(g[k][l]&&!(i&(1<<l))) { int tmp=f[i][j][k]+val[l]+val[k]*val[l]; if(g[j][l]) tmp+=val[j]*val[k]*val[l]; if(f[i|(1<<l)][k][l]<tmp) f[i|(1<<l)][k][l]=tmp,cnt[i|(1<<l)][k][l]=cnt[i][j][k]; else if(f[i|(1<<l)][k][l]==tmp) cnt[i|(1<<l)][k][l]+=cnt[i][j][k]; } } } long long ans1=0,ans2=0; for(int i=0;i<n;i++) for(int j=0;j<n;j++) if(g[i][j]){ if(ans1<f[(1<<n)-1][i][j]) ans1=f[(1<<n)-1][i][j],ans2=cnt[(1<<n)-1][i][j]; else if(ans1==f[(1<<n)-1][i][j]) ans2+=cnt[(1<<n)-1][i][j]; } printf("%lld %lld\n",ans1,ans2/2); } }