1. 程式人生 > >【poj1185】 炮兵陣地 題解&程式碼(C++)

【poj1185】 炮兵陣地 題解&程式碼(C++)

題目連結:
http://poj.org/problem?id=1185
題解:
經典的狀壓dp題目,和poj3254的題意很像,只不過poj3254是poj1185的簡化版,相當於炮兵的攻擊範圍減少了一,這樣的話我們發現與poj3254不同的是,這次第i行的狀態不僅會受到第i-1行的影響,還會受到i-2行的影響,按poj3254的思路來做只是相當於又多加了一重迴圈來列舉第i-2行的狀態,dp也要增加一維,好在按題中的影響範圍,列舉狀態後發現即使m=10也只有60種狀態滿足,因此100×60×60×60不會超時,且100×60×60也開的下。
程式碼:

#include<iostream>
#include<algorithm>
#include<stdio.h> #include<string.h> using namespace std; int n,m,sta[65]; long long dp[105][65][65]; int map[105]; char s[15]; int judge(int x)//判斷狀態x是否滿足不互相攻擊 { if ((x&(x<<1))!=0 || (x&(x<<2))!=0) return 0; return 1; } int sum(int x)//計算狀態x放置了多少個炮兵 { int su=0
; x=sta[x]; for (int i=0;i<m;i++) if (((1<<i)&x)!=0) su++; return su; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) { scanf("%s",s); for (int j=0;j<m;j++) { if (s[j]=='H') map[i]+=(1<<j); } } int
tot=0; for (int i=0;i<(1<<m);i++) if (judge(i)) { tot++; sta[tot]=i; } //cout<<tot<<endl; memset(dp,0,sizeof(dp)); //dp[i][j][k]表示第i行狀態為j且第i-1行狀態為k時最多安放幾個炮兵 for (int i=1;i<=tot;i++) if ((map[1]&sta[i])==0) dp[1][i][1]=sum(i); for (int i=2;i<=n;i++) for (int j=1;j<=tot;j++) { if ((sta[j]&map[i-2])!=0) continue; for (int k=1;k<=tot;k++) { if ((sta[k]&sta[j])!=0) continue; if ((sta[k]&map[i-1])!=0) continue; for (int w=1;w<=tot;w++) { if ((sta[w]&map[i])!=0) continue; if ((sta[w]&sta[j])!=0) continue; if ((sta[w]&sta[k])!=0) continue; dp[i][w][k]=max(dp[i][w][k],dp[i-1][k][j]+sum(w)); //cout<<i<<' '<<w<<' '<<k<<' '<<j<<endl; //cout<<dp[i][w][k]<<endl; } } } long long ans=0; //取最值 for (int i=1;i<=tot;i++) for (int j=1;j<=tot;j++) { if ((map[n-1]&sta[i])!=0)continue; if ((map[n]&sta[j])!=0)continue; if ((sta[i]&sta[j])!=0)continue; ans=max(dp[n][j][i],ans); } printf("%lld\n",ans); }