poj1185炮兵阵地 正确代码及错误代码分析
Solution:状态压缩
因为设置炮兵的局限性(同行两炮兵相差要大于2),一行10个数最多有60种可能性(程序计算)
其中判断可能性的好方法是:
if ((i & (i << 1))==0 && (i & (i << 2))==0
&& (i & (i >> 1))==0 && (i & (i >> 2))==0)
代表不能有左1,左2,右1,右2相邻的1
行数相差2以上,两行互相之间没有影响
if j,k,l不冲突
f[i][j][k]=max(f[i][j][k],f[i-1][k][l]+v[j])
其中i为第i行,j为第i行的状态,k为第(i-1)行的状态,l为第(i-2)行的状态,v为在第i行的状态j可以设置的炮兵数
f[i][j][k]为前i行,以j,k状态下设置的最多的炮兵数,而第i行设置炮兵只与i-1,i-2行有关(前i行中)
时间复杂度:n*f(t)*f(t)*f(t)
f(t)为一行t个数,设置炮兵的可能性
n<=100,m<=10 即 100*60*60*60=21600000
事实上,由于地形的限制(山地不能建炮兵)和行与行之间的限制(同列两炮兵相差要大于2),时间复杂度小于此
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int max(int a,int b) 5 { 6 if (a>b) 7 return a; 8 else 9 return b; 10 } 11 12 int main() 13 { 14 //100*1024*1024 15 int i,j,k,l,m,n,f[100][61][61],use[100][61],map[100]={0},s[100],v[1024]={0},ans=0,g=0; 16 int er[11]={1,2,4,8,16,32,64,128,256,512,1024}; 17 char c; 18 scanf("%d%d",&m,&n); 19 scanf("%c",&c); 20 for (i=0;i<m;i++) 21 { 22 for (j=n-1;j>=0;j--) 23 { 24 scanf("%c",&c); 25 if (c=='H') 26 map[i]+=er[j]; 27 } 28 scanf("%c",&c); 29 } 30 /* 31 for (i=0;i<m;i++) 32 printf("%d\n",map[i]); 33 printf("\n"); 34 */ 35 for (i=0;i<er[n];i++) 36 if ((i & (i << 1))==0 && (i & (i << 2))==0 37 && (i & (i >> 1))==0 && (i & (i >> 2))==0) 38 { 39 ans++; 40 s[ans]=i; 41 j=i; 42 while (j) 43 { 44 j&=(j-1); 45 v[ans]++; 46 } 47 } 48 /* 49 printf("ans=%d\n",ans); 50 for (i=0;i<er[n];i++) 51 printf("%d %d个 ",s[i],v[i]); 52 */ 53 //init 54 for (i=0;i<m;i++) 55 use[i][0]=0; 56 for (i=0;i<m;i++) 57 for (j=1;j<=ans;j++) 58 for (k=1;k<=ans;k++) 59 f[i][j][k]=0; 60 //row 61 for (i=0;i<m;i++) 62 //each row , posibility 63 for (j=1;j<=ans;j++) 64 if ((map[i] & s[j])==0) 65 { 66 use[i][0]++; 67 use[i][use[i][0]]=j; 68 69 //编号 cur + bcur + bpre 70 if (i>=2) 71 { 72 for (k=1;k<=use[i-1][0];k++) 73 if ((s[j] & s[use[i-1][k]])==0) 74 for (l=1;l<=use[i-2][0];l++) 75 if ((s[j] & s[use[i-2][l]])==0 76 && (s[use[i-1][k]] & s[use[i-2][l]])==0) 77 f[i][j][use[i-1][k]]=max(f[i][j][use[i-1][k]],f[i-1][use[i-1][k]][use[i-2][l]]+v[j]); 78 } 79 else if (i==1) 80 { 81 for (k=1;k<=use[i-1][0];k++) 82 if ((s[j] & s[use[i-1][k]])==0) 83 f[i][j][use[i-1][k]]=max(f[i][j][use[i-1][k]],f[i-1][use[i-1][k]][0]+v[j]); 84 } 85 else 86 f[i][j][0]=v[j]; 87 88 } 89 if (m!=1) 90 { 91 for (k=1;k<=use[m-1][0];k++) 92 for (l=1;l<=use[m-2][0];l++) 93 if ((s[use[m-1][k]] & s[use[m-2][l]])==0) 94 g=max(g,f[m-1][use[m-1][k]][use[m-2][l]]); 95 } 96 else 97 { 98 for (k=1;k<=use[m-1][0];k++) 99 g=max(g,f[m-1][use[m-1][k]][0]); 100 } 101 printf("%d\n",g); 102 /* 103 for (i=0;i<m;i++) 104 { 105 for (j=1;j<=ans;j++) 106 for (k=1;k<=ans;k++) 107 //printf("f[%d][%d][%d]=%d\n",i,j,k,f[i][j][k]); 108 printf("%d ",f[i][j][k]); 109 printf("\n\n"); 110 } 111 for (k=1;k<=use[m-1][0];k++) 112 for (l=1;l<=use[m-2][0];l++) 113 printf("%d %d %d\n",s[use[m-1][k]],s[use[m-2][l]],f[m-1][use[m-1][k]][use[m-2][l]]); 114 */ 115 return 0; 116 }
错误代码:
if j,k,l不冲突
f[i][j]=max(f[i][j],f[i-2][l]+v[k]+v[j]);
其中i为第i行,j为第i行的状态,k为第(i-1)行的状态,l为第(i-2)行的状态,v为在第i行的状态j可以设置的炮兵数
f[i][j]为前i行,以j状态下设置的最多的炮兵数
但是l,k可能会发生冲突,在f[i-2][l]下,第(i-1)行不能用k状态
如
第三行,在第1,4个建炮兵情况下,
8 4
HPPH
PPPP-----是以右上方的P为基础,与第三行发生冲突
HPPH
PHHP
PHHP
HPPH
PPPP
HPPH
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int max(int a,int b) 5 { 6 if (a>b) 7 return a; 8 else 9 return b; 10 } 11 12 int main() 13 { 14 int i,j,k,l,m,n,f[100][1024],use[100][60],map[100]={0},s[100],v[1024]={0},ans=0,g=0; 15 int er[11]={1,2,4,8,16,32,64,128,256,512,1024}; 16 char c; 17 scanf("%d%d",&m,&n); 18 scanf("%c",&c); 19 for (i=0;i<m;i++) 20 { 21 for (j=n-1;j>=0;j--) 22 { 23 scanf("%c",&c); 24 if (c=='H') 25 map[i]+=er[j]; 26 } 27 scanf("%c",&c); 28 } 29 /* 30 for (i=0;i<m;i++) 31 printf("%d\n",map[i]); 32 printf("\n"); 33 */ 34 for (i=0;i<er[n];i++) 35 if ((i & (i << 1))==0 && (i & (i << 2))==0 36 && (i & (i >> 1))==0 && (i & (i >> 2))==0) 37 { 38 ans++; 39 s[ans]=i; 40 j=i; 41 while (j) 42 { 43 j&=(j-1); 44 v[i]++; 45 } 46 } 47 /* 48 printf("ans=%d\n",ans); 49 for (i=0;i<er[n];i++) 50 printf("%d ",v[i]); 51 */ 52 for (i=0;i<m;i++) 53 use[i][0]=0; 54 for (i=0;i<m;i++) 55 for (j=0;j<er[i];j++) 56 f[i][j]=0; 57 //row 58 for (i=0;i<m;i++) 59 { 60 //each row , posibility 61 for (j=1;j<=ans;j++) 62 if ((map[i] & s[j])==0) 63 { 64 use[i][0]++; 65 use[i][use[i][0]]=s[j]; 66 if (i>=2) 67 { 68 for (k=1;k<=use[i-1][0];k++) 69 if ((s[j] & use[i-1][k])==0) 70 for (l=1;l<=use[i-2][0];l++) 71 if ((s[j] & use[i-2][l])==0 72 && (use[i-1][k] & use[i-2][l])==0) 73 f[i][s[j]]=max(f[i][s[j]],f[i-2][use[i-2][l]]+v[use[i-1][k]]+v[s[j]]); 74 } 75 else if (i==1) 76 { 77 for (k=1;k<=use[i-1][0];k++) 78 if ((s[j] & use[i-1][k])==0) 79 f[i][s[j]]=max(f[i][s[j]],f[i-1][use[i-1][k]]+v[s[j]]); 80 } 81 else 82 f[i][s[j]]=v[s[j]]; 83 } 84 } 85 for (i=1;i<=use[m-1][0];i++) 86 g=max(g,f[m-1][use[m-1][i]]); 87 printf("%d\n",g); 88 /* 89 for (i=0;i<m;i++) 90 { 91 for (j=0;j<er[n];j++) 92 printf("%d ",f[i][j]); 93 printf("\n"); 94 } 95 */ 96 return 0; 97 }