【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
#include
#include
#include
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;iif (((1<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;jif (s[j]=='H')
            map[i]+=(1<int tot=0;
    for (int i=0;i<(1<if (judge(i))
    {
        tot++;
        sta[tot]=i;
    }
    //cout<
    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<
                //cout<
            }
        }
    }
    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);
}

你可能感兴趣的:(poj,dp,状态压缩,oi之路,poj,DERIT的博客专栏)