玉米田----------------------------状压dp

农夫约翰的土地由M*N个小方格组成,现在他要在土地里种植玉米。

非常遗憾,部分土地是不育的,无法种植。

而且,相邻的土地不能同时种植玉米,也就是说种植玉米的所有方格之间都不会有公共边缘。

现在给定土地的大小,请你求出共有多少种种植方法。

土地上什么都不种也算一种方法。

输入格式
第1行包含两个整数M和N。

第2…M+1行:每行包含N个整数0或1,用来描述整个土地的状况,1表示该块土地肥沃,0表示该块土地不育。

输出格式
输出总种植方法对100000000取模后的值。

数据范围
1≤M,N≤12
输入样例:
2 3
1 1 1
0 1 0
输出样例:
9

解析:
这题和上一题的骑士问题很相似。骑士问题是八连通,本题是四连通

首先土地会有几块不能放的,所以把每行的土地也给二进制化。最后用每行的土地二进制与枚举的二进制数相比较就可以确定该状态可不可以了

 if(!(w[i]&state[a])) 

然后枚举(1<<m)种状态,相邻的一律不可以。接着枚举a状态到b状态是否可以转换。
状态转移方程
设:f[i][j]=f[i][a]+f[i-1][b] 表示:第i行的状态为a,如果第i-1行的状态b与i行状态a没有冲突,那么一定可以转移过来,所以f[i][a]+f[i-1][b]

#include<bits/stdc++.h>
using namespace std;
const int N=15,M=1<<N;
const int MOD=1e8;
int f[N][M];
int n,m,t;
int w[N];
vector<int> state;
vector<int> head[M];
bool check(int x)
{
    for(int i=0;i<m;i++)
    {
        if((x>>i&1)&&(x>> 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++)
        {
            cin>>t;
            w[i]+=!t*(1<<j);
        }
    } 
    for(int i=0;i<(1<<m);i++) //预处理每个状态是否可行
    {
        if(check(i))
        {
            state.push_back(i);
        }
    }
    for(int i=0;i<state.size();i++)//枚举哪些状态可转移
    {
        for(int j=0;j<state.size();j++)
        {
            int a=state[i];int b=state[j];
            if((a&b)==0)
            {
                head[i].push_back(j);
            }
        }
    }
    f[0][0]=1;
    for(int i=1;i<=n+1;i++)
    {
        for(int a=0;a<state.size();a++)
        {
            if(!(w[i]&state[a])) //判断当前状态与初始状态是否与起来为0,因为有的土地不能放
            {
                for(int b:head[a])
                {
                    f[i][a]=(f[i][a]+f[i-1][b])%MOD;
                }
            }
        }
    }
    cout<<f[n+1][0]<<endl;
}
发布了491 篇原创文章 · 获赞 11 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43690454/article/details/104610713
今日推荐