poj 1185(状态压缩DP)
poj 1185(状态压缩DP)
题意:在一个N*M的矩阵中,‘H'表示不能放大炮,’P'表示可以放大炮,大炮能攻击到沿横向左右各两格,沿纵向上下各两格,现在要放尽可能多的大炮使得,大炮之间不能相互攻击。
解析:可以发现,对于每一行放大炮的状态,只与它上面一行和上上一行的状态有关,每一行用状态压缩的表示方法,0表示不
放大炮,1表示放大炮,同样的,先要满足硬件条件,即有的地方不能放大炮,然后就是每一行中不能有两个1的距离小于
2(保证横着不互相攻击),这些要预先处理一下。然后就是状态表示和转移的问题了,因为是和前两行的状态有关,所以要开
个三维的数组来表示状态,当前行的状态可由前两行的状态转移而来。即如果当前行的状态符合前两行的约束条件(不和前两
行的大炮互相攻击),则当前行的最大值就是上一个状态的值加上当前状态中1的个数(当前行放大炮的个数)
状态表示:dp[i][j][k] 表示第i行状态为k,第i-1状态为j时的最大炮兵个数。
状态转移方程:dp[i][j][k] =max(dp[i][j][k],dp[i-1][l][j]+cot[k]); cot[k]为k状态中1的个数 ,可用位运算求得
DP边界条件:dp[1][0][i] =cot[i] 状态i能够满足第一行的硬件条件
AC代码如下:

1 #include<stdio.h> 2 int sta[1<<11],cot[1<<11],cur[105],dp[105][105][105]; 3 char g[105][15]; 4 int n,m,num; 5 int max(int a,int b) 6 { 7 return a>b?a:b; 8 } 9 void init() //预处理所有可能出现的状态 10 { 11 int i,tmp,sum,count; 12 num=0; 13 sum=1<<m; 14 for(i=0;i<sum;i++) 15 { 16 if(i&(i<<1) || i&(i<<2)) //同一行中1的距离不能小于2 17 continue; 18 sta[num]=i; 19 count=0; 20 tmp=i; 21 while(tmp) //求该状态中的二进制表示中1的个数 22 { 23 count++; 24 tmp&=(tmp-1); //将最低位的1化为0 25 } 26 cot[num++]=count; 27 } 28 } 29 int fit(int x,int y) //判断上下两行对应位置是否同为1 30 { 31 if(x&y) 32 return 0; 33 return 1; 34 } 35 void DP() 36 { 37 int i,j,k,l; 38 for(i=0;i<num;i++) //预处理第1行的情况 39 { 40 if(!fit(sta[i],cur[1])) 41 continue; 42 dp[1][0][i]=cot[i]; 43 } 44 for(i=2;i<=n;i++) 45 { 46 for(j=0;j<num;j++) 47 for(k=0;k<num;k++) 48 { 49 if(!fit(sta[k],cur[i]) || !fit(sta[j],cur[i-1]) || !fit(sta[k],sta[j])) //排除不符合条件的状态 50 continue; 51 for(l=0;l<num;l++) 52 { 53 if(!fit(sta[l],cur[i-2]) || !fit(sta[k],sta[l]) || !fit(sta[j],sta[l]) || !dp[i-1][l][j]) //排除不符合条件的状态 54 continue; 55 dp[i][j][k]=max(dp[i][j][k],dp[i-1][l][j]+cot[k]); //状态转移 56 } 57 } 58 } 59 int ans=0; 60 for(i=1;i<=n;i++) //求最多放置多少大炮 61 for(j=0;j<num;j++) 62 for(k=0;k<num;k++) 63 ans=max(ans,dp[i][j][k]); 64 printf("%d\n",ans); 65 } 66 int main() 67 { 68 int i,j; 69 char c; 70 scanf("%d%d",&n,&m); 71 for(i=1;i<=n;i++) 72 { 73 getchar(); 74 for(j=1;j<=m;j++) 75 { 76 scanf("%c",&c); 77 if(c=='H') //用二进制表示不能放置大炮的情况,便于判断 78 cur[i]+=1<<(m-j); //网上大多数的题解都是cur[i]+=1<<(j-1);反过来了,我表示很不理解,但是能AC =_=||~~~ 79 } 80 } 81 init(); 82 DP(); 83 return 0; 84 }
posted on 2013-08-04 17:17 jumpingfrog0 阅读(545) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步