【poj1185】 炮兵陣地 題解&程式碼(C++)
阿新 • • 發佈:2019-02-04
題目連結:
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);
}