P1879 [USACO06NOV]Corn Fields G(状压dp)

题目链接

 

 

f[i][j]表示前[i]行的状态为j时的合法方案数

mp[i]刻画的是土地

possi[i]判断是否合法

步骤:

1.读进来土地,把它二进制转十进制

2.判断草地是否相邻,即是否有连续的1。(i与他的左移一位和右移一位,分别做&运算,如果都都等于0,那么合法)举个例子:

比如说 6→110 (有连续的两个1,是个不合法的)

 1 1 0                 1 1 0

& 0 1 1                 1 0 1

得:0 1 0(×)            1 0 0(×)

3.再枚举每行可能状态,判断是否有种在贫瘠土地上的情况。什么叫种在贫瘠土地上呢?就是原本土地(i,j)这个格子上是个0,你却冒出来个1,就是不行的。这有两种判断合法的方式:(j&mp[i])==j和(j|mp[i])==mp[i]。仍然举个例子

 

j       0 1 0                        0 1 0

mp   0 0 1                        0 0 1

&得  0 0 0 (×)     |得: 0 1 1(×)

 

 

 

 

 

农场主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的余数。

输入输出样例

输入 #1
2 3
1 1 1
0 1 0
输出 #1
9

 

 

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
template <typename Tp>
void read(Tp &x){//read(n);
    x=0;char ch=1;int fh;
    while(ch!='-'&&(ch>'9'||ch<'0')){
        ch=getchar();
    }
    if(ch=='-'){
        fh=-1;ch=getchar();
    }else fh=1;
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+ch-'0';ch=getchar();
    }
    x*=fh;
}
inline char read1()//字符串读入挂
{
    register char ch=getchar();
    while(ch<'A'||ch>'M')ch=getchar();
    return ch;
}
const int maxn=1e6+100;
const int mod=100000000;
ll n,m,ans;
ll f[13][1<<13];
ll g[1<<12],h[1<<12],a[13][13];
ll v[13];
int main(){
    int x;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>x;
            v[i]=(v[i]<<1)+x;
        }
    }
    f[0][0]=1;
    for(int i=0;i<(1<<m);i++){
        if(!(i&(i<<1))&&!(i&(i>>1))){//判断是否该列合法,即没有连续的1 
            g[i]=1;
        }
    }
    for(int i=1;i<=n;i++){//枚举每行 
        for(int j=0;j<(1<<m);j++){//枚举可能的状态 
            if(g[j]&&(j&v[i])==j){//判断状态是否合法(没有相邻的1)且没有种在贫瘠的土地上 
                for(int k=0;k<(1<<m);k++){//找上一个合法的状态 
                    if(!(k&j)){//与该行的状态取&不为真(0)
                    //说明上一行和这一行不存在任意一行草地有公共边 
                        f[i][j]=(f[i][j]+f[i-1][k])%mod;//记录 
                    }
                }
            }
        }
    }
    for(int i=0;i<(1<<m);i++){
        ans=(ans+f[n][i])%mod;
    }
    cout<<ans<<endl;
}

 

上一篇:John Deere Service Advisor EDL V2 Diagnostic Kit


下一篇:John Deere Service Advisor EDL V2 Diagnostic Kit