POJ2288 islands and bridges

POJ2288 islands and bridges

状态压缩!

人生中首次写状压DP,不像ouuan大佬那样一遍AC,而是反复调了好久…而且代码还极丑陋…

 

题目大意:给您一张无向图,带点权。要求值最大的曼哈顿路径的值,并计数。

 

一条曼哈顿路径的值:所有点权之和,加相邻两点的乘积,加相邻三点的乘积(如果第一点和第三点连通)。

 

数据范围13,显然是状压DP。

 

状态表示:(1<<j)为1表示此点被访问过,为0则未访问过。
那么f[i][j][k]表示状态为i,最后一个点为j,倒数第二个点为k的最大值。num[i][j][k]则表示方案数。
DP的时候直接暴力循环就行了。

 

需要注意的两点:

 

  • 路径数要>>1,因为正反走只算一条线。
  • 需要特判各种状态行不行。这个是重点,巨烦人……

 

下面放上我丑陋的代码和标程,附带对拍器(对拍真好用)。

  1 #include <cstdio>
  2 #include <cstring>
  3 using namespace std;
  4 typedef long long LL;
  5 inline int read()
  6 {
  7     int ans=0;char ch=getchar();
  8     while(ch<'0'||ch>'9')
  9         ch=getchar();
 10     while(ch>='0'&&ch<='9')
 11         ans=(ans<<3)+(ans<<1)+ch-'0',ch=getchar();
 12     return ans;
 13 }
 14 int chart[14][14],V[14],n;
 15 LL f[1<<13][14][14],num[1<<13][14][14];
 16 bool check(int i,int j,int k)
 17 {
 18     return chart[j][k]&&((1<<j)&i)&&((1<<k)&i);
 19 }
 20 int cal(int x)
 21 {
 22     int a[14],ans=0;
 23     for(int i=0;i<14;i++) a[i]=bool(x&(1<<i));
 24     for(int i=13;i>=0;i--) ans=ans*10+a[i];
 25     return ans;
 26 }
 27 /**
 28 2
 29 3 3
 30 2 2 2
 31 1 2
 32 2 3
 33 3 1
 34 */
 35 void solve(int i,int j,int k)
 36 {
 37     //printf("solve:%d %d %d  %d   ",cal(i),j,k,f[i][j][k]);
 38     int t=0,ii=i;
 39     while(ii)
 40         t+=(ii&1),ii>>=1;
 41     if(t==1) return;
 42     if(t==2)
 43     {
 44         num[i][j][k]=1;
 45         f[i][j][k]=V[j]+V[k]+V[j]*V[k];
 46         //printf("%d\n",f[i][j][k]);
 47         return;
 48     }
 49     for(int x=0;x<n;x++)
 50     {
 51         if(((1<<x)&i)&&chart[x][k]&&(x!=j)&&f[i^(1<<j)][k][x])
 52         {
 53             int temp = f[i^(1<<j)][k][x] + V[j] + V[j]*V[k] + (chart[x][j])*V[x]*V[k]*V[j];
 54             //printf("x=%d temp:%d=%d+%d+%d+%d   ",x,temp,f[i^(1<<j)][k][x],V[j],V[j]*V[k],(chart[x][j])*V[x]*V[k]*V[j]);
 55             if(temp>f[i][j][k])
 56             {
 57                 f[i][j][k]=temp;
 58                 num[i][j][k]=num[i^(1<<j)][k][x];
 59             }
 60             else if(temp==f[i][j][k])
 61                 num[i][j][k]+=num[i^(1<<j)][k][x];
 62         }
 63     }
 64     //printf("%d\n",f[i][j][k]);
 65     return;
 66 }
 67 int main()
 68 {
 69     //freopen("my.in","r",stdin);
 70     //freopen("my.out","w",stdout);
 71     int T = read();
 72     while(T--)
 73     {
 74         n=read();
 75         int m=read(),x,y;
 76         int N = 1<<n;
 77         for(int i=1;i<=n;i++) V[i-1]=read();
 78         for(int i=1;i<=m;i++)
 79         {
 80             x=read();y=read();
 81             x--;y--;
 82             chart[x][y]=chart[y][x]=1;
 83         }
 84         if(n==1)
 85         {
 86             printf("%d 1\n",V[0]);
 87             continue;
 88         }
 89         ///初始化
 90         for(int i=0;i<n;i++)
 91         {
 92             f[1<<i][i][0]=V[i];
 93             num[1<<i][i][0]=1;
 94         }
 95         ///DP
 96         for(int i=1;i<N;i++)
 97         {
 98             for(int j=0;j<n;j++)
 99             {
100                 for(int k=0;k<n;k++)
101                 {
102                     if(check(i,j,k)) solve(i,j,k);
103                 }
104             }
105         }
106         ///统计答案
107         LL ans=0,ans2=0;
108         for(int j=0;j<n;j++)
109         {
110             for(int k=0;k<n;k++)
111             {
112                 if(ans<f[N-1][j][k])
113                 {
114                     ans=f[N-1][j][k];
115                     ans2=num[N-1][j][k];
116                 }
117                 else if(ans==f[N-1][j][k])
118                 {
119                     ans2+=num[N-1][j][k];
120                 }
121             }
122         }
123         printf("%I64d %I64d\n",ans,ans2>>1);
124         ///
125         memset(f,0,sizeof(f));
126         memset(num,0,sizeof(num));
127         memset(chart,0,sizeof(chart));
128     }
129     return 0;
130 }
AC代码
  1 /*
  2     Author: Yuanhao Li, Peking University
  3     本程序仅供参考
  4 */
  5 #include <iostream>
  6 #include <cstdio>
  7 #include <algorithm>
  8 #include <cmath>
  9 #include <cstdio>
 10 #include <cstring>
 11 using namespace std;
 12 
 13 const int MAX_N = 13;
 14 
 15 int f[1 << MAX_N][MAX_N][MAX_N]; // f[i][j][k]: Current state i, Just passed l, j, k (1, 2, ..., l, j, k)
 16 long long cnt[1 << MAX_N][MAX_N][MAX_N];
 17 
 18 void DP(bool graph[MAX_N][MAX_N], int value[MAX_N], int n)
 19 {
 20     if (n == 1)
 21     {
 22         printf("%d %d\n", value[0], 1);
 23         return;
 24     }
 25 
 26     memset(f, 0, sizeof(f));
 27     memset(cnt, 0, sizeof(cnt));
 28 
 29     for (int i = 0; i < n; i++)
 30     {
 31         for (int j = 0; j < n; j++)
 32         {
 33             if (graph[i][j] && i != j)
 34             {
 35                 f[(1 << i) + (1 << j)][i][j] = value[i] + value[j] + value[i] * value[j];
 36                 cnt[(1 << i) + (1 << j)][i][j] = 1;
 37             }
 38         }
 39     }
 40 
 41     for (int i = 1; i < 1 << n; i++)
 42     {
 43         for (int j = 0; j < n; j++) if (i >> j & 1)
 44             for (int k = 0; k < n; k++) if ((i >> k & 1) && graph[j][k])
 45                 for (int l = 0; l < n; l++) if ((i >> l & 1) && graph[l][j] && (f[i ^ (1 << k)][l][j] > 0))
 46                 {
 47                     int newVal = f[i ^ (1 << k)][l][j] +
 48                         value[k] +
 49                         value[j] * value[k] +
 50                         (int)(graph[l][k]) * value[l] * value[j] * value[k];
 51                     if (newVal > f[i][j][k])
 52                     {
 53                         f[i][j][k] = newVal;
 54                         cnt[i][j][k] = cnt[i ^ (1 << k)][l][j];
 55                     }
 56                     else if (newVal == f[i][j][k])
 57                     {
 58                         cnt[i][j][k] += cnt[i ^ (1 << k)][l][j];
 59                     }
 60                 }
 61     }
 62 
 63     int result = 0;
 64     long long duplicate = 0;
 65     for (int j = 0; j < n; j++)
 66         for (int k = 0; k < n; k++)
 67         {
 68             if (f[(1 << n) - 1][j][k] > result)
 69             {
 70                 result = f[(1 << n) - 1][j][k];
 71                 duplicate = cnt[(1 << n) - 1][j][k];
 72             }
 73             else if (f[(1 << n) - 1][j][k] == result)
 74             {
 75                 duplicate += cnt[(1 << n) - 1][j][k];
 76             }
 77         }
 78 
 79     printf("%d %lld\n", result, duplicate / 2);
 80 }
 81 
 82 int main()
 83 {
 84     freopen("my.in","r",stdin);
 85     freopen("right.out","w",stdout);
 86     int q;
 87     cin >> q;
 88     while (q--)
 89     {
 90         int n, m;
 91         cin >> n >> m;
 92         int value[MAX_N];
 93         bool graph[MAX_N][MAX_N];
 94         memset(value, 0, sizeof(value));
 95         memset(graph, false, sizeof(bool) * MAX_N * MAX_N);
 96 
 97         for (int i = 0; i < n; i++)
 98         {
 99             scanf("%d", &value[i]);
100         }
101         for (int i = 0; i < m; i++)
102         {
103             int a, b;
104             scanf("%d %d", &a, &b);
105             graph[a - 1][b - 1] = true;
106             graph[b - 1][a - 1] = true;
107         }
108 
109         DP(graph, value, n);
110     }
111 
112     return 0;
113 }
标程
 1 #include <cstdio>
 2 #include <ctime>
 3 #include <windows.h>
 4 using namespace std;
 5 int a[15][15];
 6 int main()
 7 {
 8     freopen("my.in","w",stdout);
 9     srand((unsigned)(time(NULL)));
10     printf("1\n");
11     int n=rand()%12+2;
12     printf("%d  ",n);
13     int m=rand()%(n*n/2-n/2)+1;
14     printf("%d\n",m);
15     for(int i=1; i<=n; i++) printf("%d ",rand()%100+1);
16     printf("\n");
17     int i=0;
18     while(i<m)
19     {
20         int p1=rand()%n+1;
21         int p2=rand()%n+1;
22         if(p1!=p2&&!a[p1][p2])
23         {
24             a[p1][p2]=a[p2][p1]=1;
25             printf("%d %d\n",p1,p2);
26             i++;
27         }
28     }
29 
30     return 0;
31 }
数据生成器

那么再见~~~~~

 

posted @ 2018-05-05 17:41  garage  阅读(202)  评论(0编辑  收藏  举报