UESTC 882 冬马党 --状压DP

定义:dp[i][j]为状态为j时,第i行符合条件的状态数

转移方程:dp[i][j] += dp[i-1][t]   //t为上一行状态,与当前行不冲突。

从第一行开始向下枚举,每次枚举当前行的状态和上一行的状态,如果不相邻或者未被地雷占据并且两行的关系是合法的,则加上方法数。

最后res = SUM(dp[n][s]) (s=0~S,为最后一行的状态)

代码:

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cmath>

#include <algorithm>

#define Mod 1000000007

using namespace std;

#define N 100000000



//dp[i][j]:状态为j时,第i行符合条件的状态数

int wei[14];

int a[2070];

int dp[14][2070];



int checkadj(int state)

{

    if(state & (state<<1))   //相邻

        return 0;

    return 1;

}



int checkplace(int state,int i)

{

    if(state & wei[i])     //被地雷占据

        return 0;

    return 1;

}



int main()

{

    int n,m,i,j,k,state;

    scanf("%d%d",&n,&m);

    memset(wei,0,sizeof(wei));

    memset(dp,0,sizeof(dp));

    for(i=1;i<=n;i++)

    {

        for(j=1;j<=m;j++)

        {

            scanf("%d",&state);

            if(!state)

                wei[i] += (1<<(m-j));  //被地雷占据赋为1

        }

    }

    int Fst = 1<<m;

    k = 0;

    for(state=0;state<Fst;state++)   //第一行

    {

        if(checkadj(state))

        {

            a[k++] = state;

            if(checkplace(state,1))

                dp[1][k-1] = 1;

        }

    }

    for(i=2;i<=n;i++)

    {

        for(j=0;j<k;j++)   //枚举上一行

        {

            if(!checkplace(a[j],i-1))

                continue;

            for(state=0;state<k;state++)  //枚举这一行

            {

                if(!checkplace(a[state],i) || (a[j] & a[state]))

                    continue;

                dp[i][state] = (dp[i][state] + dp[i-1][j])%N;

            }

        }

    }

    int res = 0;

    for(i=0;i<k;i++)

        res = (res + dp[n][i])%N;

    printf("%d\n",res);

    return 0;

}
View Code

 

你可能感兴趣的:(dp)