acwing状态压缩

小国王(井字型DP)

![在这里插入图片描述]( https://img-blog.csdnimg.cn/59534b3fc91047d894c1f7b0425027dc.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw,size_20,color_FFFFFF,t_70,g_se,x_16)
思路
![在这里插入图片描述]( https://img-blog.csdnimg.cn/1d02bf79a0794142b046c7b9bb6ddca4.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw
,size_20,color_FFFFFF,t_70,g_se,x_16)

样例输入:

3 2

样例输出:

16

代码模板:

#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

typedef long long LL;

const int N = 12, M = 1 << 10, K = 110;

int n, m;
vector<int> state;
int cnt[M];
vector<int> head[M];
LL f[N][K][M];

bool check(int state)
{
    for (int i = 0; i < n; i ++ )
        if ((state >> i & 1) && (state >> i + 1 & 1))
            return false;
    return true;
}

int count(int state)
{
    int res = 0;
    for (int i = 0; i < n; i ++ ) res += state >> i & 1;
    return res;
}

int main()
{
    cin >> n >> m;

    for (int i = 0; i < 1 << n; i ++ )
        if (check(i))
        {
            state.push_back(i);
            cnt[i] = count(i);
        }

    for (int i = 0; i < state.size(); i ++ )
        for (int j = 0; j < state.size(); j ++ )
        {
            int a = state[i], b = state[j];
            if ((a & b) == 0 && check(a | b))
                head[i].push_back(j);
        }

    f[0][0][0] = 1;
    for (int i = 1; i <= n + 1; i ++ )
        for (int j = 0; j <= m; j ++ )
            for (int a = 0; a < state.size(); a ++ )
                for (int b : head[a])
                {
                    int c = cnt[state[a]];
                    if (j >= c)
                        f[i][j][a] += f[i - 1][j - c][b];
                }

    cout << f[n + 1][m][0] << endl;

    return 0;
}

 

玉米田(十字型DP)

![在这里插入图片描述]( https://img-blog.csdnimg.cn/05353f2870de414498b63a794119249f.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw==,size_20,color_FFFFFF,t_70,g_se,x_16)
样例输入:

2 3
1 1 1
0 1 0

样例输出:

9

代码模板:

#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 14, M = 1 << 12, mod = 1e8;

int n, m;
int w[N];
vector<int> state;
vector<int> head[M];
int f[N][M];

bool check(int state)     //判断是否存在相邻土地种了玉米
{
    for (int i = 0; i + 1 < m; i ++ )
        if ((state >> i & 1) && (state >> i + 1 & 1))
            return false;
    return true;
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ )
        for (int j = 0; j < m; j ++ )
        {
            int t;
            cin >> t;
            w[i] += !t * (1 << j);
        }

    for (int i = 0; i < 1 << m; i ++ )  //行相邻之间没有连续的1状态
        if (check(i))
            state.push_back(i);

    for (int i = 0; i < state.size(); i ++ )    //并且一列没有相邻的1的所有状态
        for (int j = 0; j < state.size(); j ++ )//预处理上一行状态为a下一行状态为b且合法的所有状态
        {
            int a = state[i], b = state[j];
            if (!(a & b))
                head[i].push_back(j);
        }

    f[0][0] = 1;
    for (int i = 1; i <= n + 1; i ++ )
        for (int j = 0; j < state.size(); j ++ )
            if (!(state[j] & w[i]))     //如果状态j与土地本身冲突(即不合法),则continue
                for (int k : head[j])
                    f[i][j] = (f[i][j] + f[i - 1][k]) % mod;

    cout << f[n + 1][0] << endl; //小技巧 不用遍历最后一行

    return 0;
}

 

炮兵阵地(十字形DP)

![在这里插入图片描述]( https://img-blog.csdnimg.cn/9bc39136af7a45928e818b5b849edb51.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw==,size_20,color_FFFFFF,t_70,g_se,x_16)
样例输入:

5 4
PHPP
PPHH
PPPP
PHPP
PHHP

样例输出:

6

代码模板:

#include <iostream>
#include <vector>
using namespace std;
const int N = 110, M = 10, S = 1 << M;
int n, m;
int f[2][S][S];//滚动数组
vector<int> state;
int g[N];
int cnt[S];

// 检查状态是否合法
bool check(int s) {
    for (int i = 0; i < m; i ++ ) 
        if ((s >> i & 1) && ((s >> i + 1 & 1) || (s >> i + 2 & 1))) return false;
    return true;
}

//检查状态s中有多少个1,即有多少个位置摆了炮兵
int count(int s) {
    int cnt = 0;
    while (s) {
        cnt += s & 1;
        s >>= 1;
    }
    return cnt;

}


int main() {
    cin >> n >> m;
    //g[i]表示第i行的0(P)和1(H)的位置摆放情况
    for (int i = 0; i < n; i ++ ) {
        for (int j = 1; j <= m; j ++ ) {
            char c;
            cin >> c;
            if (c == 'H') g[i] += 1 << (m - j);
        }
    }
    //合法位置的集合;
    for (int i = 0; i < 1 << m; i ++ ) {
        if (check(i)) {
            state.push_back(i);
            cnt[i] = count(i);
        }

    }

    for (int i = 0; i <= n + 1; i ++ )
        for (int j = 0; j < state.size(); j ++ )
            for (int k = 0; k < state.size(); k ++ )
                for (int u = 0; u < state.size(); u ++ ) {
                    //a 表示 i - 1行状态, b表示第i行状态, c表示第i - 2行状态
                    int a = state[j], b = state[k], c = state[u];
                    if ((a & b) || (a & c) || (b & c)) continue;//列
                    if (g[i] & b) continue;
                    f[i & 1][a][b] = max(f[i & 1][a][b], f[i - 1 & 1][c][a] + cnt[b]);
                }
    cout << f[n + 1 & 1][0][0] << endl;
    return 0;
}

 

posted @ 2022-03-22 14:30  panse·  阅读(31)  评论(0)    收藏  举报