POJ_1185_炮兵阵地 dp+状态压缩
题目:炮兵阵地
链接:http://poj.org/problem?id=1185
解题思路:
首先用 int 来表示每一行的情况,比如说第一行是k1,那么【 k1&(k1>>2) | k1&(k1>>1) 】就可以排除一行中相邻的和隔一格的。。。
地形也可以用 int (取反)来表示,比如说第一行是PPHPH,给他记作m1=00101(二进制数),1表示不能存放,那么对于一个数a,判断a是不是符合地形就可以用【 a & m1 】来表示,如果与出来的是真,那么说明存在某一位1&1的情景,就表示不符合。
下一行是否能和上一行共存也用位运算来进行,比如下一行是s2,上一行是s1,那么【 s2 & s1 】为真就表示不能共存。
上面是通过位运算来巧妙解决可行存放问题的方法。
贴代码了:
1 #include<stdio.h> 2 #include<string.h> 3 /* 4 改进。。。 5 */ 6 char s[100][11]; 7 int mp[100]; 8 int ans[60],ao; 9 int dp[100][60][60]; 10 /* 11 dp[i][j][k]: 第i行 - 上一行是ans[j]、本行是ans[k]的情况下,最多数量为多少。 12 因为有了两行的间隔,上面的炮台就不会影响到下面的,所以只要记录两行的所有情况,两行相同的可以计算出最大值了 13 */ 14 //因为列数最多为10,所以无视地形,一行最多有60中存放方式 15 void func(int m) 16 { 17 for(int i=0;i<(1<<m);i++) 18 { 19 if(i&(i>>1)||i&(i>>2)) continue; 20 ans[ao++]=i; 21 } 22 } 23 int count(int x) 24 { 25 int co=0; 26 while(x) 27 { 28 co+=x&1; 29 x>>=1; 30 } 31 return co; 32 } 33 int pre[100][10000],po,ko,lo; 34 int main() 35 { 36 int n,m; 37 while(scanf("%d%d",&n,&m)!=EOF) 38 { 39 for(int i=0;i<n;i++) 40 { 41 scanf("%s",s[i]); 42 } 43 memset(mp,0,sizeof(mp)); 44 for(int i=0;i<n;i++) 45 { 46 for(int j=0;j<m;j++) 47 { 48 if(s[i][j]=='H') mp[i]=mp[i]|(1<<j); 49 } 50 } 51 ao=0; 52 func(m); 53 memset(dp,0,sizeof(dp)); 54 po=0; 55 for(int i=0;i<ao;i++) 56 { 57 if(mp[0]&ans[i]) continue; 58 int tmp=count(ans[i]); 59 dp[0][0][i]=tmp; 60 pre[0][po++]=i; //记录第0行所有存值情况,po为总数 61 } 62 if(n==1) 63 { 64 int mt=0; 65 for(int i=0;i<po;i++) 66 { 67 int line1=pre[0][i]; //因为前面只有一行,所以只需要考虑pre[0][i]的情况 68 if(dp[0][0][line1]>mt) mt=dp[0][0][line1]; 69 } 70 printf("%d\n",mt); 71 continue; 72 } 73 ko=0; 74 for(int i=0;i<po;i++) 75 { 76 for(int j=0;j<ao;j++) 77 { 78 int line1=pre[0][i]; 79 if(ans[j]&mp[1]) continue; 80 if(ans[line1]&ans[j]) continue; 81 int tmp=count(ans[j]); 82 dp[1][line1][j]=dp[0][0][line1]+tmp; 83 pre[2][ko]=line1; //到下一行时,这里就是上两行,下面的就是上一行,先用2暂存,最终再移入0 84 pre[1][ko++]=j; 85 } 86 } 87 for(int i=0;i<ko;i++) 88 pre[0][i]=pre[2][i]; 89 bool v[70][70]; 90 for(int i=2;i<n;i++) 91 { 92 lo=0; 93 memset(v,0,sizeof(v)); 94 for(int k=0;k<ko;k++) 95 { 96 int line1=pre[i-2][k],line2=pre[i-1][k]; //上两行和上一行的情况 97 if(v[line1][line2]) continue; //因为有很多重复的,去重 98 v[line1][line2]=1; 99 for(int u=0;u<ao;u++) 100 { 101 if(ans[u]&mp[i]) continue; //如果与本身的地形不符,就跳过 102 if(ans[u]&ans[line1]||ans[u]&ans[line2]) continue; //如果和前两行矛盾就跳过 103 int tmp=count(ans[u]); //如果都满足条件,就计算这一行这种放法增加的数量 104 if(dp[i-1][line1][line2]+tmp>dp[i][line2][u]) 105 { 106 dp[i][line2][u]=dp[i-1][line1][line2]+tmp; 107 pre[i+1][lo]=line2; //先用i+1的存放,等k的循环结束再移到i-1 108 pre[i][lo++]=u; 109 } 110 } 111 } 112 for(int u=0;u<lo;u++) 113 pre[i-1][u]=pre[i+1][u]; 114 ko=lo; 115 } 116 int mt=0; 117 for(int j=0;j<ko;j++) 118 { 119 int line1=pre[n-2][j],line2=pre[n-1][j]; 120 if(mt<dp[n-1][line1][line2]) mt=dp[n-1][line1][line2]; 121 } 122 printf("%d\n",mt); 123 } 124 return 0; 125 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架