状压DP初识~~炮兵阵地
炮兵阵地
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 31718 | Accepted: 12253 |
Description
司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
Input
第一行包含两个由空格分割开的正整数,分别表示N和M;
接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。
接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。
Output
仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。
Sample Input
5 4 PHPP PPHH PPPP PHPP PHHP
Sample Output
6
题意:中文题面,题意很明显了
我们来考虑一下最暴力的搜索每个点都尝试一遍的话会是1000!
肯定是会爆炸的,所以,既然每行的列数在10以内,那么我们很自然的就想到了状态压缩的dp
将每一行的状态存储为一个二进制数,1表示可以放,0表示不能放
每一层的状态由上一层推导而来,如果上层这个地方放了,那么下面的这个地方就不能放
所以我们要用到二进制的位运算
dp[r][j][i]=max(dp[r−1][k][j]+sum[i])
其中sum[i]sum[i]为i状态对应的数量
代码如下:
(参考上海全能王博客
http://cubercsl.cn/solve/2017-summer/emplacement/
#include <cstdio> #include <algorithm> #include <iostream> #include <cstring> #include <vector> #include <set> #include <map> #include <cmath> #include <queue> #include <stack> using namespace std; const int maxn =105; const int INF = 0x3f3f3f3f; const int mod = 1e9+7; const double eps = 1e-6; int dp[maxn][maxn][maxn]; int maze[maxn]; vector<int> v,sum; inline bool ok(int s){ return !(s&(s<<1))&&!(s&(s<<2)); } inline int getsum(int s){ int ret=0; for(;s;s>>=1){ if(s&1) ret++; } return ret; } void init(int m){ for(int i=0;i <(1<<m);i++){ if(ok(i)){ v.push_back(i); sum.push_back(getsum(i)); } } } int main(){ int n,m; char tmp; cin>>n>>m; init(m); memset(dp,0xc0,sizeof(dp)); for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ cin>>tmp; if(tmp=='H') maze[i]|=(1<<j); } } for(int i=0;i<v.size();i++){ if(!(v[i]&maze[0])){ dp[0][0][i]=sum[i]; } } for(int r=1;r<n;r++) for(int i=0;i<v.size();i++) if(!(v[i]&maze[r])) for(int j=0;j<v.size();j++) if(!(v[i]&v[j])) for(int k=0;k<v.size();k++) if(!(v[i]&v[k])) dp[r][j][i]=max(dp[r][j][i],dp[r-1][k][j]+sum[i]); int ans=0; for(int i=0;i<v.size();i++){ for(int j=0;j<v.size();j++){ ans=max(ans,dp[n-1][i][j]); } } cout<<ans<<endl; return 0; }
每一个不曾刷题的日子
都是对生命的辜负
从弱小到强大,需要一段时间的沉淀,就是现在了
~buerdepepeqi