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
",res);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/whatbeg/p/3762740.html