[POJ2288]Islands and Bridges

状压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);
}
}

猜你喜欢

转载自www.cnblogs.com/sdfzhsz/p/9369112.html