POJ 1185 炮兵阵地 【状压DP】
<題目鏈接>
題目大意:
司令部的將軍們打算在N*M的網(wǎng)格地圖上部署他們的炮兵部隊(duì)。一個(gè)N*M的地圖由N行M列組成,地圖的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下圖。在每一格平原地形上最多可以布置一支炮兵部隊(duì)(山地上不能夠部署炮兵部隊(duì));一支炮兵部隊(duì)在地圖上的攻擊范圍如圖中黑色區(qū)域所示:?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
如果在地圖中的灰色所標(biāo)識(shí)的平原上部署一支炮兵部隊(duì),則圖中的黑色的網(wǎng)格表示它能夠攻擊到的區(qū)域:沿橫向左右各兩格,沿縱向上下各兩格。圖上其它白色網(wǎng)格均攻擊不到。從圖上可見(jiàn)炮兵的攻擊范圍不受地形的影響。?
現(xiàn)在,將軍們規(guī)劃如何部署炮兵部隊(duì),在防止誤傷的前提下(保證任何兩支炮兵部隊(duì)之間不能互相攻擊,即任何一支炮兵部隊(duì)都不在其他支炮兵部隊(duì)的攻擊范圍內(nèi)),在整個(gè)地圖區(qū)域內(nèi)最多能夠擺放多少我軍的炮兵部隊(duì)。
輸入:
第一行包含兩個(gè)由空格分割開(kāi)的正整數(shù),分別表示N和M;?
接下來(lái)的N行,每一行含有連續(xù)的M個(gè)字符('P'或者'H'),中間沒(méi)有空格。按順序表示地圖中每一行的數(shù)據(jù)。N <= 100;M <= 10。
輸出:
僅一行,包含一個(gè)整數(shù)K,表示最多能擺放的炮兵部隊(duì)的數(shù)量。
解題分析:
從形式和數(shù)據(jù)范圍來(lái)看,不難看出是一道狀壓DP的題。因?yàn)榈?i$行與前兩行的狀態(tài)有關(guān),所以我們這里用$dp[i][j][k]$來(lái)表示第$i$行為第$j$種狀態(tài),$k$則表示上一行的狀態(tài)。
#include <cstdio> #include <algorithm> using namespace std;const int MAXR = 110, MAXC = 15, MAXM = 70; #define legal(a,b) a&bint n,m,top; int base[MAXR],state[MAXM],num[MAXM],dp[MAXR][MAXM][MAXM]; //dp[i][j][k],表示第i行,j表示第i行的狀態(tài),k表示第i-1行的狀態(tài) char graph[MAXR][MAXC]; inline bool ok(int x){ //在同一行的角度下,先判斷這個(gè)狀態(tài)是否可行if(x&(x<<1) || x&(x<<2))return false;return true; } inline int Count(int x){ //計(jì)算這個(gè)狀態(tài)下,該行所放士兵的數(shù)量int ans=0;while(x){ans+=x&1;x>>=1;}return ans; } inline void init(){top=0;for(int i=0;i<(1<<m);i++){if(!ok(i))continue;num[top]=Count(i); //記錄每個(gè)狀態(tài)對(duì)應(yīng)士兵的數(shù)量state[top++]=i; //預(yù)處理出初始的所有可行狀態(tài) } } int main(){scanf("%d%d",&n,&m);for(int i=0;i<n;i++){scanf("%s",graph[i]);for(int j=0;j<m;j++)if(graph[i][j]=='H')base[i]+=1<<j;}init();for(int i=0;i<top;i++){ //初始化第一行if(legal(state[i],base[0]))continue;dp[0][i][0]=num[i];}for(int i=0;i<top;i++){ //初始化第二行 ,i表示第二行的狀態(tài)if(legal(state[i],base[1]))continue;for(int j=0;j<top;j++){ //j表示第一行的狀態(tài)if(legal(state[j],base[0]))continue;if(legal(state[i],state[j]))continue;dp[1][i][j]=max(dp[1][i][j],dp[0][j][0]+num[i]);}}for(int r=2;r<n;r++){ //枚舉第r行for(int i=0;i<top;i++){ //第r行的狀態(tài)if(legal(state[i],base[r]))continue;for(int j=0;j<top;j++){ //第r-1行的狀態(tài)if(legal(state[j],base[r-1]))continue;if(legal(state[i],state[j]))continue;for(int k=0;k<top;k++){ //第r-2行的狀態(tài)if(legal(state[k],base[r-2]))continue;if(legal(state[j],state[k]))continue;if(legal(state[i],state[k]))continue;dp[r][i][j]=max(dp[r][i][j],dp[r-1][j][k]+num[i]);}}}}int ans=0;for(int i=0;i<top;i++)for(int j=0;j<top;j++)ans=max(ans,dp[n-1][i][j]); //從最后一行的所有狀態(tài)中挑選一個(gè)最大的printf("%d\n",ans); }?
轉(zhuǎn)載于:https://www.cnblogs.com/00isok/p/10593748.html
總結(jié)
以上是生活随笔為你收集整理的POJ 1185 炮兵阵地 【状压DP】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: OpenGL学习笔记(2) 画一个正方形
- 下一篇: 【面向对象】第一单元总结——表达式求导