NKOJ P1902 [UASCO 2006 GOLD] 玉米地【状态压缩】

问题描述

Farmer John买了一片土地,可以表示为一片由方块组成的网格,长度为M,宽度为N(1 <= M, N <= 12)。现在FJ要在地里种上一些玉米让他的奶牛们直接在地里食用。FJ知道他的这片土地有些地方很贫瘠,没有办法种玉米;并且奶牛们不喜欢挨在一起吃玉米,所以不能在相邻的两块地上种玉米。请帮助FJ计算一下所有可能的种玉米的方案数。注意,结果输出对于100,000,000的余数,一棵玉米也不中也算是一种方案。


把每一行的状态存入 L i n e [ ]

f [ i ] [ j ] 表示 1 i 行,并且第 i 行状态为 j 时的合法方案数。

考虑状态的转移,既然要求转移合法,我们就来考虑一下合法的条件:

1. 当前枚举的状态 j 与对应的 L i n e [ i ] 不冲突,

2. 当前枚举的状态 j 与上一层的某状态 k 不冲突,

3. 当前枚举的状态自身没有连续的 1

如果枚举出来的当前层状态 j 与上一层状态 k 满足上面三个条件,就可以进行累加转移:

f [ i ] [ j ] + = f [ i 1 ] [ k ]

然后初始化 f [ 1 ] [ ] 即可。

#include <bits/stdc++.h>
using namespace std;
const int Mod=1e8;
const int Inf=1e9;
int DP[13][1<<13];
int N,M,T,Ans,Line[13],Map[13][13];
int main(){
    int I,J,K;
    scanf("%d%d",&N,&M);T=(1<<M)-1;
    for(I=1;I<=N;I++){
        for(J=1;J<=M;J++){
            scanf("%d",&Map[I][J]);
            if(Map[I][J]==1){
                Line[I]=Line[I]|(1<<(J-1));
            }
        }
    }
    for(I=0;I<=T;I++){
        if((I|Line[1])==Line[1]&&((I>>1)&I)==0&&(I&(I<<1))==0){
            DP[1][I]=1;
        }
    }
    for(I=2;I<=N;I++){
        for(J=0;J<=T;J++){
            for(K=0;K<=T;K++){
                if((J|Line[I])==Line[I]&&(J&K)==0&&((J>>1)&J)==0&&(J&(J<<1))==0){
                    DP[I][J]=(DP[I][J]+DP[I-1][K])%Mod;
                }
            }
        }
    }
    for(I=0;I<=T;I++){
        Ans=(Ans+DP[N][I])%Mod;
    }
    printf("%d",Ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yanzhenhuai/article/details/81623361
今日推荐