1. 程式人生 > >P1879 [USACO06NOV]玉米田Corn Fields (狀壓dp入門)

P1879 [USACO06NOV]玉米田Corn Fields (狀壓dp入門)

題目連結: https://www.luogu.org/problemnew/show/P1879

具體思路: 我們可以先把所有合法的情況枚舉出來,然後對第一行判斷有多少種情況滿足,然後對於剩下的行數,我們可以繼續列舉,但是列舉的時候要注意,要判斷一下和它的上面一行的各種情況會不會衝突,然後一直列舉就可以了.

注意點:位運算子的優先順序比等號之類的低,所以如果要判斷的話,最好放在括號裡面判斷.

AC程式碼:

 

#include<bits/stdc++.h>
using namespace std;
# define ll long long
const int maxn = 10000+100;
# define inf 0x3f3f3f3f
const int mod = 1e9;
int Map[maxn];
int a[maxn][maxn];
int dp[maxn][maxn];
int ok[maxn];
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]);
            Map[i]=(Map[i]<<1)+a[i][j];//把初始的圖存起來
        }
    }
    int maxstate=(1<<m)-1;//所有情況
    for(int i=0; i<=maxstate; i++)
    {
        if((((i<<1)&i)==0)&(((i>>1)&i)==0))//如果當前這種情況符合,只有他的左邊和右邊都不會有相鄰的1
        {
            ok[i]=1;
        }
    }
    for(int i=0; i<=maxstate; i++)
    {
        if((ok[i]==1)&(((i&Map[1])==i)))
        {
            dp[1][i]=1;
        }
    }//列舉第一行
    for(int i=2; i<=n; i++)
    {
        for(int j=0; j<=maxstate; j++)
        {
            if(ok[j]&((j&Map[i])==j))
            {
                for(int k=0; k<=maxstate; k++)
                {
                    if(((j&k)==0)&ok[k])
                        dp[i][j]=(dp[i][j]+dp[i-1][k])%mod;
                }
            }
        }
    }
    ll sum=0;
    for(int i=0; i<=maxstate; i++)
    {
        sum=(sum+dp[n][i])%mod;
    }
    printf("%lld\n",sum);
    return 0;
}