状压dp(POJ - 1185 炮兵阵地 )

种菜的那个题的升级版,不过比较简单。搞清楚三个判断函数就好了:

che() 判断本行状态是否符合(一行中炮兵相隔最小为2)
chc() 判断这特定的一行是不是符合(只能放在P上)
chzh()判断两行是否冲突。

下面是ac代码:

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <queue>
#include <stack>
#define ll long long
using namespace std;
const int N = 128;
int zhua[N];
int hang[N];
int w[N];
int dp[N][N][N];
inline bool chc(int i, int j)
{
  //  cout << i << " " << j << ":" << endl;
  //  cout << hang[i] << " " <<zhua[j] <<endl;
    if ((hang[i]|zhua[j]) == hang[i]) return 1;
    return 0;
}
inline bool chzh(int j, int k)
{
    if ((zhua[j]|zhua[k]) == zhua[j] + zhua[k]) return 1;
    return 0;
}
inline bool che(int m)
{
    if (!(m&(m>>1)) && !(m&(m>>2))) return 1;
    return 0;
}
int init(int m)
{
    int len = 0;
    int mx = (1<<m) - 1;
    for (int i = 0; i <= mx; i++)
    {
        if (che(i))
        {
            zhua[len] = i;
            int t0 = i;
            int cnt = 0;
            while(t0)
            {
                if (t0&1) cnt++;
                t0>>=1;
            }
            w[len++] = cnt;
        }
    }
    return len;
}
char su[55];
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    int len = init(m);
  //  cout << len << endl;
    for (int i = 1; i <= n; i++)
    {
        scanf("%s", su);
        for (int j = 0; j < m; j++)
            hang[i] = hang[i]<<1 | (su[j]=='P'?1:0);
    }
    for (int i = 1; i <= n; i++)
    {
        if (i == 1)
        {
            for (int j = 0; j < len; j++)
            {
                if (chc(i, j)) dp[i][j][0] += w[j];
            }
        }
        else if (i == 2)
        {
            for (int j = 0; j < len; j++)
            {
                if (chc(i, j))
                {
                    for (int k = 0; k < len; k++)
                    {
                        if (chc(i-1, k) && chzh(k, j)) dp[i][j][k] = max(dp[i][j][k], dp[i-1][k][0] + w[j]);
                    }
                }
            }
        }
        else
        {
            for (int j = 0; j < len; j++)
            {
                if (chc(i, j))
                {
                    for (int k = 0; k < len; k++)
                    {
                        if (chc(i-1, k))
                        {

                            for (int g = 0; g < len; g++)
                            {
                                if (chc(i-2, g))
                                {
                                    if (chzh(j, k) && chzh(j, g) && chzh(g, k))
                                    {
                                        dp[i][j][k] = max(dp[i][j][k], dp[i-1][k][g] + w[j]);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    int ans = 0;
   /* for (int i = 1; i <= n; i++)
    {
        for (int j = len-1; j >= 0; j--)
        for (int j = len-1; j >= 0; j--)
            cout <<dp[i][j][] << " ";
        cout << endl;
    }*/
    for (int k = 0; k < len; k++)
    {
        for (int i = 0; i < len; i++)
        {
            if (chc(n, i) && chc(n-1, k) && chzh(i, k)) ans = max(ans, dp[n][i][k]);
        }
    }
    printf("%d\n", ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值