C - 炮兵阵地 (状态dp)
2017-12-03 23:31
204 查看
题意:
类似于上面一道题,一个方格组成的矩阵,每个方格可以放大炮用0表示,不可以放大炮用1表示(原题用字母),让放最多的大炮,大炮与大炮间不会互相攻击。
解析:
可以发现,对于每一行放大炮的状态,只与它上面一行和上上一行的状态有关,每一行用状态压缩的表示方法,0表示不放大炮,1表示放大炮,同样的,先要满足硬件条件,即有的地方不能放大炮,然后就是每一行中不能有两个1的距离小于2(保证横着不互相攻击),这些要预先处理一下。然后就是状态表示和转移的问题了,因为是和前两行的状态有关,所以要开个三维的数组来表示状态,当前行的状态可由前两行的状态转移而来。即如果当前行的状态符合前两行的约束条件(不和前两行的大炮互相攻击),则当前行的最大值就是上一个状态的值加上当前状态中1的个数(当前行放大炮的个数)
【状态表示】dp[i][j][k] 表示第i行状态为k,第i-1状态为j时的最大炮兵个数。
【状态转移方程】dp[i][k][t] =max(dp[i][k][t],dp[i-1][j][k]+num[t]); num[t]为t状态中1的个数
【DP边界条件】dp[1][1][i] =num[i] 状态i能够满足第一行的硬件条件(注意:这里的i指的是第i个状态,不是一个二进制数,开一个数组保存二进制状态)
代码:
类似于上面一道题,一个方格组成的矩阵,每个方格可以放大炮用0表示,不可以放大炮用1表示(原题用字母),让放最多的大炮,大炮与大炮间不会互相攻击。
解析:
可以发现,对于每一行放大炮的状态,只与它上面一行和上上一行的状态有关,每一行用状态压缩的表示方法,0表示不放大炮,1表示放大炮,同样的,先要满足硬件条件,即有的地方不能放大炮,然后就是每一行中不能有两个1的距离小于2(保证横着不互相攻击),这些要预先处理一下。然后就是状态表示和转移的问题了,因为是和前两行的状态有关,所以要开个三维的数组来表示状态,当前行的状态可由前两行的状态转移而来。即如果当前行的状态符合前两行的约束条件(不和前两行的大炮互相攻击),则当前行的最大值就是上一个状态的值加上当前状态中1的个数(当前行放大炮的个数)
【状态表示】dp[i][j][k] 表示第i行状态为k,第i-1状态为j时的最大炮兵个数。
【状态转移方程】dp[i][k][t] =max(dp[i][k][t],dp[i-1][j][k]+num[t]); num[t]为t状态中1的个数
【DP边界条件】dp[1][1][i] =num[i] 状态i能够满足第一行的硬件条件(注意:这里的i指的是第i个状态,不是一个二进制数,开一个数组保存二进制状态)
代码:
#include <cstdio> #include <cstring> using namespace std; #define max(a,b) (a) > (b) ? (a) : (b) int N,M; char map[110][20],num[110],top; int stk[70],cur[110]; int dp[110][70][70]; inline bool ok(int x){ //判断该状态是否合法,即不存在相邻的1之间的距离小于3的 if(x&(x<<1)) return 0; if(x&(x<<2)) return 0; return 1; } //找到所有可能的合法状态,最多60种 inline void jinit() { top=0; int i,total=1<<N; for(i=0;i<total;i++) if(ok(i)) stk[++top]=i; } //判断状态x是否与第k行匹配 inline bool fit(int x,int k) { if(cur[k]&x) return 0; return 1; } //数一个整型数x的二进制中1的个数(用于初始化) inline int jcount(int x) { int cnt=0; while(x) { cnt++; x&=(x-1); } return cnt; } int main(){ while(scanf("%d%d",&M,&N) != EOF){ if(N == 0 && M == 0)break; jinit(); for(int i = 1; i <= M; ++i)scanf("%s",map[i]+1); for(int i = 1; i <= M; ++i) for(int j = 1; j <= N; ++j){ cur[i]=0; for(j=1;j<=N;j++){ if(map[i][j]=='H')cur[i]+=(1<<(j-1)); } } memset(dp,-1,sizeof(dp)); //初始化第一行状态 for(int i = 1;i <= top;i++){ num[i]=jcount(stk[i]); if(fit(stk[i],1)) dp[1][1][i]=num[i]; } int i,t,j,k; for(i = 2;i <= M;i++){ for(t = 1;t <= top;t++){ if(!fit(stk[t],i)) continue; for(j = 1;j <= top;j++) { if(stk[t]&stk[j])continue; for(k = 1;k <= top;k++) { if(stk[t]&stk[k])continue; if(dp[i-1][j][k]==-1)continue; dp[i][k][t] =max(dp[i][k][t],dp[i-1][j][k]+num[t]); } } } } int ans = 0; for(i = 1; i <= M; ++i) for(j = 1; j <= top; ++j) for(k = 1; k <= top; ++k) ans = max(ans,dp[i][j][k]); printf("%d\n",ans); } return 0; }
相关文章推荐
- poj 1185 状态压缩dp-炮兵阵地
- POJ 3254 炮兵阵地(状态压缩DP)
- 状态压缩dp入门题 POJ 1185 炮兵阵地
- 一、状态压缩dp(3)炮兵阵地
- POJ 1185 炮兵阵地(状态dp)
- poj 1185 炮兵阵地(状态压缩DP)
- POJ 1185 炮兵阵地(状态压缩DP)
- 状压DP ( 预处理减少状态 )——炮兵阵地 (POJ 1185)
- poj 1185 炮兵阵地 状态压缩+dp sum dp,s,Map
- poj 1185 炮兵阵地 (压缩状态DP)
- POJ1185炮兵阵地(DP状态压缩)
- poj 1185 炮兵阵地 状态压缩dp
- POJ 1185 炮兵阵地(状态压缩dp)
- poj1185炮兵阵地--状态dp
- 状态压缩dp_POJ1185炮兵阵地
- poj 1185 炮兵阵地 【状态压缩dp】
- Poj 1185 炮兵阵地 【状态压缩dp】
- POJ 1185 炮兵阵地 ( dp[状态压缩] )
- 状态压缩dp入门题目总结——炮兵阵地和TSP问题
- poj 1185 炮兵阵地 (状态压缩dp~)