POJ 3254 簡單狀態壓縮DP

現在對簡單題的態度也變了,覺得簡單題未必不能幫助你提高。簡單題往往更裸,更能單獨體現某一個知識點或者技巧。而複雜題目往往是幾種技巧的組合使用。

這是一道入門的狀態壓縮DP。

在一個棋盤上選擇一些不相鄰的點(上下左右),求這些點的總數。有一些點不可選。

首先把每行可能的狀態保存下來。存在state裏面,因爲限制了不相鄰,所以這樣一輪篩選之後單行的狀態數就已經少了很多。

然後對每一行i 枚舉所有可能到達這個狀態的 i-1行的狀態。因爲狀態只和上一行有關。然後求和就可以了。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

int dp[20][500];
const int MOD=100000000;
int tot;
int state[500];
void init(int n)
{
    int k=1<<n;
    for(int i=0;i<k;i++)
    {
        if((i&(i<<1))==0)
            state[tot++]=i;
    }
}
int row[100];
int main()
{
    int m,n;
    scanf("%d%d",&m,&n);
    memset(row,0,sizeof(row));
    memset(dp,0,sizeof(dp));
    memset(state,0,sizeof(state));

    init(n);
    for(int i=0;i<m;i++)
    {
        for(int j=n-1;j>=0;j--)
        {
            int k;
            scanf("%d",&k);
            row[i]+=(k<<j);
        }
    }
    for(int i=0;i<tot;i++)
    {
        if( ( row[0] & state[i] ) == state[i] )
            dp[0][i]=1;//代表第i個狀態 不表示狀態是i
    }
    for(int i=1;i<m;i++)
    {
        for(int j=0;j<tot;j++)//本行狀態
        {
            if((row[i]&state[j])==state[j])//可滿足
            {
                for(int k=0;k<tot;k++)//前一行狀態
                {
                    if(dp[i-1][k]&&(((state[k])&state[j])==0))
                    {
                        dp[i][j]=(dp[i-1][k]+dp[i][j])%MOD;
                    }
                }
            }
        }
    }
    int sum=0;
    for(int i=0;i<tot;i++)
    {
        sum=(sum+dp[m-1][i])%MOD;
    }
    printf("%d\n",sum);
    return 0;

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章