【题解】洛谷P1879 [USACO06NOV] Corn Fields(状压DP)

洛谷P1879:https://www.luogu.org/problemnew/show/P1879

思路

把题目翻译成人话

在n*m的棋盘 每个格子不是0就是1

1表示可以种 0表示不能种 相邻的格子不能同时种 求总方案数

把每行看成一个n位的2进制数 预处理出每行的状态后 进行DP即可

PS:在处理每行的初始状态时 将其取反后更好操作

代码

#include<iostream>
#include<cstdio>
using namespace std;
#define mod 100000000
int f[15][1010];
int n,m,ans;
struct State
{
    int st[5000];
    int num;
}a[15];
void getstate(int i,int t)
{
    int num=0;//记录此行有几种状态 
    for(int j=0;j<(1<<n);j++)//枚举所有状态 
    {
        if((j&t)||(j&(j<<1))||(j&(j>>1))) continue;//如果冲突就跳过 
        a[i].st[++num]=j;//记录状态 
        a[i].num=num;
    }
}
void dp()
{
    for(int i=1;i<=a[1].num;i++) f[1][i]=1;//初始化 
    for(int i=2;i<=m;i++)//枚举行 
    {
        for(int j=1;j<=a[i].num;j++)//枚举第i行的状态 
        {
            f[i][j]=0;
            for(int k=1;k<=a[i-1].num;k++)//枚举第i-1行的状态 
            {
                if(a[i].st[j]&a[i-1].st[k]) continue;//如果冲突就跳过 
                f[i][j]+=f[i-1][k];//累计ans 
            }
        }
    }
    for(int i=1;i<=a[m].num;i++)
    ans=(ans+f[m][i])%mod;//累计第m行的所有状态的ans 
    printf("%d",ans);
}
int main()
{
    scanf("%d%d",&m,&n);
    for(int i=1;i<=m;i++)
    {
        int t=0;//处理当前行的状态 
        for(int j=1;j<=n;j++)
        {
            int x;
            cin>>x;//这里对输入进行取反操作 
            t=(t<<1)+1-x;//如1010 存成0101 方便后面判断状态 
        }
        getstate(i,t);//获得此行状态 
    }
    dp();
}

猜你喜欢

转载自www.cnblogs.com/BrokenString/p/9812230.html