poj 2288 Islands and Bridges

题意:

定义一个最优哈密顿回路如果把如下描述的值最大化:

有n个城市。一个哈密顿回路C1C2..Cn的值由3个部分组成:

1.这个路径上每个岛的值Vi之和;

2.这个路径上每条边Vi*Vi+1之和;

3.如果路径上连续的三个岛屿CiCi+1Ci+2之间两两互相连通,那么就加上Vi*Vi+1*Vi+2。

求出最优哈密顿回路的值以及个数。

(一条路径及其反转,认为是同一条路径)。

思路:

首先,计算值肯定是跟前两个岛有关系的,此时就可以用当前状态为S,前两个岛为i,前一个岛为j来进行状态的转移。

dp[S|(1<<k)][j][k] = max(dp[S|(1<<k)][j][k],dp[S][i][j] + v[k] + v[j]*v[k] + v[j]*v[k]*v[i]),最后一个部分必须满足两两互相连通才能加。

如果dp[S|(1<<k)][j][k]已经有值并且与当前计算出来的值相同,路径条数直接加上即可。

最后路径条数要减半,因为逆序的路径也是计算了的。

注意dp数组的初始化。

代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <algorithm>
  4 using namespace std;
  5 const int N = 14;
  6 int dp[1<<N][N][N];
  7 long long num[1<<N][N][N];
  8 int v[N];
  9 bool mp[N][N];
 10 int main()
 11 {
 12     int t;
 13     scanf("%d",&t);
 14     while (t--)
 15     {
 16         int n,m;
 17         scanf("%d%d",&n,&m);
 18         memset(mp,0,sizeof(mp));
 19         memset(dp,-1,sizeof(dp));
 20         memset(num,0,sizeof(num));
 21         for (int i = 0;i < n;i++) scanf("%d",&v[i]);
 22         for (int i = 0;i < m;i++)
 23         {
 24             int x,y;
 25             scanf("%d%d",&x,&y);
 26             x--,y--;
 27             mp[x][y] = mp[y][x] = 1;
 28         }
 29         if (n == 1)
 30         {
 31             printf("%d 1\n",v[0]);
 32             continue;
 33         }
 34         for (int i = 0;i < n;i++)
 35         {
 36             for (int j = 0;j < n;j++)
 37             {
 38                 if (i == j) continue;
 39                 if (!mp[i][j]) continue;
 40                 dp[(1<<i)|(1<<j)][i][j] = v[i] + v[j] + v[i]*v[j];
 41                 num[(1<<i)|(1<<j)][i][j] = 1;
 42             }
 43         }
 44         for (int i = 0;i < (1<<n);i++)
 45         {
 46             for (int j = 0;j < n;j++)
 47             {
 48                 for (int k = 0;k < n;k++)
 49                 {
 50                     if (j == k) continue;
 51                     if (!mp[j][k]) continue;
 52                     if (dp[i][j][k] < 0) continue;
 53                     for (int l = 0;l < n;l++)
 54                     {
 55                         if (i&(1<<l)) continue;
 56                         if (!mp[k][l]) continue;
 57                         int tmp = v[l] + v[k] * v[l];
 58                         if (mp[j][k] && mp[j][l] && mp[l][k])
 59                         {
 60                             tmp += v[j]*v[k]*v[l];
 61                         }
 62                         if (dp[i|(1<<l)][k][l] < dp[i][j][k] + tmp)
 63                         {
 64                             dp[i|(1<<l)][k][l] = dp[i][j][k] + tmp;
 65                             num[i|(1<<l)][k][l] = num[i][j][k];
 66                         }
 67                         else if (dp[i|(1<<l)][k][l] == dp[i][j][k] + tmp)
 68                         {
 69                             num[i|(1<<l)][k][l] += num[i][j][k];
 70                         }
 71                     }
 72                 }
 73             }
 74         }
 75         int maxn = -1;
 76         long long cnt = 0;
 77         for (int i = 0;i < n;i++)
 78         {
 79             for (int j = 0;j < n;j++)
 80             {
 81                 if (i == j) continue;
 82                 maxn = max(dp[(1<<n)-1][i][j],maxn);
 83             }
 84         }
 85         if (maxn == -1) printf("0 0\n");
 86         else
 87         {
 88             for (int i = 0;i < n;i++)
 89             {
 90                 for (int j = 0;j < n;j++)
 91                 {
 92                     if (i == j) continue;
 93                     if (dp[(1<<n)-1][i][j] == maxn) cnt += num[(1<<n)-1][i][j];
 94                 }
 95             }
 96             printf("%d %lld\n",maxn,cnt/2);
 97         }
 98     }
 99     return 0;
100 }

 

posted @ 2018-04-17 00:48  qrfkickit  阅读(151)  评论(0编辑  收藏  举报