首页 > 代码库 > poj2288(状压dp)

poj2288(状压dp)

题意:给出n个点,m条边的无向图,给出每个点的点权,求点权和最小的哈密顿路径,相邻两个点要加上点权的乘积,形成环要加上环上的点权

哇,这个题wa了好多发,后来发现是因为存在一个特殊情况,即n==1时需要特判,哎,还是自己想的不周到

技术分享
  1 #include<string>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<iostream>
  5 #include<vector>
  6 #include<cmath>
  7 #include<algorithm>
  8 #include<queue>
  9 using namespace std;//题意:给出n个点,m条边的无向图,给出每个点的点权,求点权和最小的哈密顿路径,相邻两个点要加上点权的乘积,形成环要加上环上的点权
 10 typedef long long ll;
 11 ll dp[15][15][1<<14];
 12 ll nums[15][15][1<<14];
 13 bool map[15][15];
 14 ll val[15];
 15 int n,m;
 16 int main()
 17 {
 18     int i,j,T,k,l;
 19     scanf("%d",&T);
 20     while(T--)
 21     {
 22         scanf("%d%d",&n,&m);
 23         ll add=0;
 24         for(i=0;i<n;i++)scanf("%lld",&val[i]),add+=val[i];
 25         memset(map,0,sizeof(map));
 26         memset(nums,0,sizeof(nums));
 27         memset(dp,-1,sizeof(dp));
 28         while(m--)
 29         {
 30             int a,b;
 31             scanf("%d%d",&a,&b);
 32             a--,b--;
 33             map[a][b]=map[b][a]=1;
 34         }
 35         if(n==1)
 36         {
 37             printf("%d 1\n",val[0]);
 38             continue;
 39         }
 40         for(i=0;i<n;i++)
 41         {
 42             for(j=0;j<n;j++)
 43             {
 44                 if(i==j)continue;
 45                 if(!map[i][j])continue;
 46                 dp[i][j][(1<<i)|(1<<j)]=val[i]*val[j];
 47                 nums[i][j][(1<<i)|(1<<j)]=1;
 48             }
 49         }
 50         for(i=0;i<(1<<n);i++)
 51         {
 52             for(j=0;j<n;j++)//back
 53             {
 54                 if(i&(1<<j)==0)continue;
 55                 for(k=0;k<n;k++)//front
 56                 {
 57                     if(j==k)continue;
 58                     if(i&(1<<k)==0)continue;
 59                     if(nums[k][j][i]==0)continue;
 60                     if(dp[k][j][i]==-1)continue;
 61                     for(l=0;l<n;l++)
 62                     {
 63                         if(map[l][k]==0)continue;
 64                         if(l==j||l==k)continue;
 65                         if(i&(1<<l))continue;
 66                         ll gain=val[l]*val[k];
 67                         if(map[l][j])
 68                         {
 69                             gain+=val[l]*val[k]*val[j];
 70                         }
 71                         int state=i|(1<<l);
 72                         if(dp[l][k][state]==dp[k][j][i]+gain)
 73                         {
 74                             nums[l][k][state]+=nums[k][j][i];
 75                         }
 76                         else if(dp[l][k][state]<dp[k][j][i]+gain)
 77                         {
 78                             dp[l][k][state]=dp[k][j][i]+gain;
 79                             nums[l][k][state]=nums[k][j][i];
 80                         }
 81                     }
 82                 }
 83             }
 84         }
 85         ll num=0,ans=-1;
 86         for(i=0;i<n;i++)
 87         {
 88             for(j=0;j<n;j++)
 89             {
 90                 if(i==j||map[i][j]==0)continue;
 91                 if(!nums[i][j][(1<<n)-1])continue;
 92                 if(dp[i][j][(1<<n)-1]==-1)continue;
 93                 if(ans<dp[i][j][(1<<n)-1])
 94                 {
 95                     ans=dp[i][j][(1<<n)-1];
 96                     num=nums[i][j][(1<<n)-1];
 97                 }
 98                 else if(ans==dp[i][j][(1<<n)-1])
 99                 {
100                     num+=nums[i][j][(1<<n)-1];
101                 }
102             }
103         }
104         if(ans==-1)
105         {
106             printf("0 0\n");
107             continue;
108         }
109         printf("%lld %lld\n",ans+add,num/2);
110     }
111 
112 }
View Code

 

poj2288(状压dp)