状态压缩

例1

P1879 [USACO06NOV]玉米田Corn Fields

农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地。John打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。

遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是John不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。

John想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)

输入输出格式

输入格式:
第一行:两个整数M和N,用空格隔开。

第2到第M+1行:每行包含N个用空格隔开的整数,描述了每块土地的状态。第i+1行描述了第i行的土地,所有整数均为0或1,是1的话,表示这块土地足够肥沃,0则表示这块土地不适合种草。

输出格式:
一个整数,即牧场分配总方案数除以100,000,000的余数。

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

    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= m; j++){
            cin >> t;
            map[i] = (map[i] << 1) + t;
        }
    }

    int state = 1 << m;
    //  处理状态i是否合法
    for (int i = 0; i < state; i++){
        if ( ( (i << 1) & i)  == 0 && ( ( (i >> 1) & i) == 0 )  )
            can[i] = 1;
    }

    // f[i][j] 表示前i行,且第i行的状态为j的方案数
    for (int i = 0; i < state; i++){
        if (can[i] && ( i & map[1] ) == i ){
            f[1][i] = 1;
        }    
    }

    for (int i = 2; i <= n; i++){
        for (int j = 0; j < state; j++){
            // 如果j是一个合法的状态
            if (can[j] && (j & map[i]) == j){
                for (int k = 0; k < state; k++){
                    // 如果上一行的状态j与i不冲突
                    if ( (k & j) == 0){
                        f[i][j] = (f[i][j] + f[i - 1][k]) % mod;
                    }
                }
            }
        }
    }
    long long ans = 0;
    for (int i = 0; i < state; i++)
        ans = (ans + f[n][i]) % mod;
    cout << ans;
}

例2

[SCOI2005]互不侵犯

题目描述
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。

注:数据有加强(2018/4/25)

输入格式
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

输出格式
所得的方案数

输入输出样例
输入 #1复制
3 2
输出 #1复制
16

#include <iostream>
using namespace std;

int n, m;
const int N = 10;
int f[N][1 << N][N * N];

int cnt = 0;
int s[1 << N];
int c[1 << N];
int maxstate;
int count(int x)
{
    int ans = 0;
    while (x)
    {
        ans++;
        x -= (x & (-x));
    }
    return ans;
}

void init()
{
    for (int i = 0; i < maxstate; i++)
    {
        if (i & (i << 1)) continue;
        s[++cnt] = i;
        c[cnt] = count(i);
    }
}


int main()
{
    cin >> n >> m;
    maxstate = 1 << n;
    init();
    
    for (int i = 1; i <= cnt; i++)
        f[1][i][c[i]] = 1;
    
    for (int i = 2; i <= n; i++)
    {
        for (int j = 1; j <= cnt; j++) // 本层状态
        {
            for (int k = 1; k <= cnt; k++) // 上次状态
            {
                if ( (s[k] & s[j]) || ( (s[k] << 1) & s[j] ) || ( (s[k] >> 1) & s[j] ) ) continue;
                
                for (int p = c[j]; p <= m; p++)
                    f[i][j][p] += f[i - 1][k][p - c[j]];
            }
        }
    }
    
    long long ans = 0;
    for (int i = 1; i <= cnt; i++)
        ans += f[n][i][m];
    cout << ans;
}
posted @ 2020-04-15 10:24  keik  阅读(110)  评论(0)    收藏  举报