ACWING327. 玉米田(状压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

思路: 基础状压,f(i,j)表示到了第i行状态为j有多少种放置方式。

ACNEW :把状态预处理一遍

#include 
#include 
#include 

using namespace std;

typedef long long ll;
const int mod = 1e9;

ll sta[1 << 13],a[13];
ll f[13][1 << 13];
ll right[1 << 13];

bool judge1(ll s)
{
    if(s & (s << 1))return false;
    return true;
}

bool judge2(ll s1,ll s2)
{
    if(s1 & s2)return false;
    return true;
}

bool judge3(ll s1,ll s2)
{
    if((s1 | s2) != s1)return false;
    return true;
}

int main()
{
    ll n,m;scanf("%lld%lld",&n,&m);
    for(ll i = 1;i <= n;i++)
    {
        for(ll j = 0;j < m;j++)
        {
            ll tmp;scanf("%lld",&tmp);
            if(tmp)
            {
                a[i] = a[i] | (1 << j);
            }
        }
    }
    
    ll cnt = 0;
    for(ll i = 0;i < (1 << m);i++)
    {
        if(judge1(i) && judge3(a[1],i))f[1][i] = 1;
        if(judge1(i))right[++cnt] = i;
    }
    
    for(ll i = 2;i <= n;i++)
    {
        for(ll now = 1;now <= cnt;now++)
        {
            if(judge3(a[i],right[now]))
            {
                for(ll pre = 1;pre <= cnt;pre++)
                {
                    if(judge2(right[now],right[pre]))
                    {
                        f[i][right[now]] += f[i - 1][right[pre]];
                    }
                }
            }
        }
    }
    
    ll ans = 0;
    for(ll i = 0;i < (1 << m);i++)
    {
        ans = (ans + f[n][i]) % mod;
    }
    
    printf("%lld\n",ans);
    return 0;
}

#include 
#include 
#include 
#include 

using namespace std;

const int MOD = 100000000;
int f[13][1 << 12],a[13][13],sta[13];

bool ok2(int s1,int s2)
{
    if((s1 & s2) == 0)
        return true;
    return false;
}

bool ok3(int s)
{
    if((s & (s >> 1)) == 0)
        return true;
    return false;
}

int main()
{
    int n,m;scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++)
    {
        for(int j = 1;j <= m;j++)
        {
            scanf("%d",&a[i][j]);
            if(a[i][j] == 1)
                sta[i] |= (1 << (j - 1));
        }
    }
    
    for(int i = 0;i < (1 << m);i++)
    {
        if(((i & sta[1]) == i) && ok3(i))
            f[1][i] = 1;
    }
    
    for(int i = 2;i <= n;i++)
    {
        for(int j = 0;j < (1 << m);j++)
        {
            if(ok3(j) && ((j & sta[i]) == j))
            {
                for(int k = 0;k < (1 << m);k++)
                {
                    if(!(j & k))
                    {
                        f[i][j] = (f[i - 1][k] + f[i][j]) % MOD;;
                    }
                }
            }
        }
    }
    
    int ans = 0;
    for(int j = 0;j < (1 << m);j++)
        ans = (ans + f[n][j]) % MOD;
    
    printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(#,算法竞赛进阶指南,#,状压dp)