炮兵阵地(POJ-1185)
Problem Description
司令部的將軍們打算在N*M的網(wǎng)格地圖上部署他們的炮兵部隊。一個N*M的地圖由N行M列組成,地圖的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下圖。在每一格平原地形上最多可以布置一支炮兵部隊(山地上不能夠部署炮兵部隊);一支炮兵部隊在地圖上的攻擊范圍如圖中黑色區(qū)域所示:?
如果在地圖中的灰色所標識的平原上部署一支炮兵部隊,則圖中的黑色的網(wǎng)格表示它能夠攻擊到的區(qū)域:沿橫向左右各兩格,沿縱向上下各兩格。圖上其它白色網(wǎng)格均攻擊不到。從圖上可見炮兵的攻擊范圍不受地形的影響。?
現(xiàn)在,將軍們規(guī)劃如何部署炮兵部隊,在防止誤傷的前提下(保證任何兩支炮兵部隊之間不能互相攻擊,即任何一支炮兵部隊都不在其他支炮兵部隊的攻擊范圍內(nèi)),在整個地圖區(qū)域內(nèi)最多能夠擺放多少我軍的炮兵部隊。?
Input?
第一行包含兩個由空格分割開的正整數(shù),分別表示N和M;?
接下來的N行,每一行含有連續(xù)的M個字符('P'或者'H'),中間沒有空格。按順序表示地圖中每一行的數(shù)據(jù)。N <= 100;M <= 10。
Output
僅一行,包含一個整數(shù)K,表示最多能擺放的炮兵部隊的數(shù)量。
Sample Input
5 4
PHPP
PPHH
PPPP
PHPP
PHHP
Sample Output
6
思路:狀壓DP
思路來源:點擊這里
用一個三維數(shù)組按層數(shù)來進行狀態(tài)的轉(zhuǎn)移,依次枚舉每一層(i)、當前層狀態(tài)(j)、上一層狀態(tài)(k)、上上層狀態(tài)(l),即可進行轉(zhuǎn)移
關(guān)于枚舉狀態(tài),理論上每一行都有 1<<m 種可能,如果依次枚舉一定會 TLE,但實際上,因為 m 最大為10,且每3個不相鄰,因此每一行的最多狀態(tài)數(shù)只有60種可能。
因此對于狀態(tài) x,只需右移一位后與原數(shù)進行與運算判斷是否為零,即可快速的判斷其是否存在互相攻擊的情況。
原理:如果二進制位的每一個 1 都是被大于等于 1 個零隔開的,那么錯位之后絕對不會出現(xiàn)兩個 1 位于同一個位置上,所以 & 起來之后一定是為 0,反之如果不為 0,則說明至少有一個地方是出現(xiàn)了兩個 1 相連的。
Source Program
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<string> #include<cstdlib> #include<queue> #include<set> #include<map> #include<stack> #include<ctime> #include<vector> #define INF 0x3f3f3f3f #define PI acos(-1.0) #define N 1001 #define MOD 10007 #define E 1e-6 #define LL long long using namespace std; int n,m; int len; int dp[110][70][70]; int num[110],sta[110]; int Map[110]; bool check(int x)//判斷狀態(tài)是否合法 {if((x&(x<<1))||(x&(x<<2)))return false;return true; } int Get_Num(int x)//取x狀態(tài)共有多少個1 {int cnt=0;while(x){cnt++;x&=(x-1);}return cnt; } bool judge(int x,int a)//判斷是否與上一層狀態(tài)合法 {if(x&a)return false;return true; } int main() {while(scanf("%d%d",&n,&m)!=EOF&&(n+m)){len=0;memset(Map,0,sizeof(Map));memset(dp,-1,sizeof(dp));memset(num,0,sizeof(num));memset(sta,0,sizeof(sta));for(int i=0;i<(1<<m);i++){if(check(i)){sta[len]=i;num[len++]=Get_Num(i);}}char str[201];for(int i=0;i<n;i++){scanf("%s",str);for(int j=0;j<m;j++)if(str[j]=='H')//存圖,將‘H’認為會沖突的點,將一個字符串狀態(tài)壓縮成一個數(shù)Map[i]+=(1<<j);}int res=0;for(int i=0;i<len;i++){if(judge(sta[i],Map[0])){dp[0][0][i]=num[i];res=max(num[i],res);}}for(int i=1;i<n;i++)//枚舉層數(shù)for(int j=0;j<len;j++)//枚舉當前狀態(tài)if(judge(sta[j],Map[i]))for(int k=0;k<len;k++)//枚舉上一層狀態(tài)if(judge(sta[j],sta[k]))for(int l=0;l<len;l++)//枚舉上上層狀態(tài)if(judge(sta[j],sta[l])&&dp[i-1][k][l]!=-1){dp[i][l][j]=max(dp[i-1][k][l]+num[j],dp[i][l][j]);res=max(dp[i][l][j],res);}cout<<res<<endl;}return 0; }?
新人創(chuàng)作打卡挑戰(zhàn)賽發(fā)博客就能抽獎!定制產(chǎn)品紅包拿不停!總結(jié)
以上是生活随笔為你收集整理的炮兵阵地(POJ-1185)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 和为给定数(信息学奥赛一本通-T1244
- 下一篇: 最大子矩阵(信息学奥赛一本通-T1224