动态规划---状压dp

Posted dukelv

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划---状压dp相关的知识,希望对你有一定的参考价值。

状压dp,就是把动态规划之中的一个个状态用二进制表示,主要运用位运算。

这里有一道例题:蓝书P639猛兽军团1

直接上代码,注释很详细

#include<cstdio>
#include<iostream>
#include<cstring>
#define N 15
#define M 110
#define MAX 550
using namespace std;
/*
见蓝书641页
*/
int s[MAX]; // 记录一行可能的状态
int num[MAX]; //s数组对应每个状态放了多少个猛兽
int states;
long long f[N][M][MAX]; //f[i][j][k]第i行状态为k,放了j个猛兽
int n,m;
void init_state() //预处理s,num数组,代表一行之内所有的可能性
{
    states = 0;
    for(int i = 0; i < (1 << n); i++) //注意,这里是枚举状态
    {
        if(i & (i << 1)) //处理一排上的冲突情况
            continue;
        int t = i;
        num[states] = 0;
        while(t)
        {
            num[states] += (t & 1);
            t = t >> 1;
        }
        s[states++] = i;  //保存状态
    }
}
void dp()
{
    int a,c,mm,b,cc;
    long long ans;
    memset(f,0,sizeof(f));
    //单独算第一行和最后一行
    for(int i = 0; i < states; i++)
    {
        int j = num[i];
        if(j <= m)  //不能超过总数
            f[1][j][i]++;
    }
    for(int i = 2; i < n; i++) //2~n - 1行
    {
        for(int j = 0; j <= m; j++) // 到第i行,一共放了j个猛兽
        {
            for(a = 0; a < states; a++) //i行状态
            {
                c = num[a];
                if(c > j)
                    continue;
                mm = j - c;//前i - 1行的总数
                for(int b = 0; b < states; b++) //枚举i-1行
                {
                    cc = num[b];
                    if(cc > mm)
                        continue;
                    if(s[a] & s[b]) //上下有攻击
                        continue;
                    if(s[a] & (s[b] << 1)) //对角有攻击
                        continue;
                    if(s[b] & s[a] << 1) // 同上
                        continue;
                    f[i][j][a] += f[i - 1][mm][b];
                }
            }
        }
    }
    ans = 0;
    for(a = 0; a < states; a++) //最后一行
    {
        c = num[a];
        if(c > m)
            continue;
        int j = m - c;
        for(int b = 0; b < states; b++) //枚举n-1行
        {
            cc = num[b];
            if(cc > j)
                continue;
            if(s[a] & s[b]) //上下有攻击
                continue;
            if(s[a] & (s[b] << 1)) //对角有攻击
                continue;
            if(s[b] & s[a] << 1) // 同上
                continue;
            f[n][m][a] += f[n - 1][j][b];
        }
        ans += f[n][m][a];
    }
    printf("%lld
",ans);
}
int main()
{
    scanf("%d%d",&n,&m);
    init_state();
    dp();
    return 0;
}

 

以上是关于动态规划---状压dp的主要内容,如果未能解决你的问题,请参考以下文章

动态规划-状压DP(炮兵阵地)

[bzoj3717][PA2014]Pakowanie_动态规划_状压dp

[bzoj1879][Sdoi2009]Bill的挑战_动态规划_状压dp

HDU5117 Fluorescent 期望 计数 状压dp 动态规划

状压DP(超详细!!!)

ACM - 动态规划小白入门:背包 / 线性 / 区间 / 计数 / 数位统计 / 状压 / 树形 / 记忆化 DP