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 }
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 }
那么再见~~~~~