【POJ3254】Corn Fields(状态压缩DP)

来源:互联网 发布:淘宝热搜关键词排行榜 编辑:程序博客网 时间:2024/06/05 16:06

记录一个菜逼的成长。。

一道状态压缩DP入门的题。学习下状压DP。
题目大意:
给你一个n*m的图。为0不能放羊,为1可以放羊,一个格子只能放一只羊,并且不能有羊相邻的情况有多少种。

状态压缩就是将状态用一个十进制数来表示,十进制数用二进制表示就可以表示状态,所以会用到位运算。
dp[i][j]:=第i行状态为j的方案数;
对于可以放羊的位置,如果放羊则为1,不放则为0;
样例第一行有8种情况,分别为 000,001,010,100,011(不符),101,110(不符),111(不符)
第二行有两种情况,分别为000,010
而010这种情况又跟第一行的010冲突,所以对于000情况又5种,对于010有4种,加起来是9种。
所以判断的时候不仅要判断同行相邻,还要判断与上一行相邻的情况。
对于样例,m = 3,所以将状态压缩为8.即1<<3。在二进制下有三位,可以用来表示状态。

#include <cstdio>#include <iostream>#include <cstring>#include <string>#include <algorithm>#include <cstdlib>#include <vector>#include <set>#include <map>#include <queue>#include <list>#include <stack>#include <deque>#include <cctype>#include <bitset>#include <cmath>using namespace std;#define ALL(v) (v).begin(),(v).end()#define cl(a) memset(a,0,sizeof(a))#define fin freopen("D://in.txt","r",stdin)#define fout freopen("D://out.txt","w",stdout)typedef long long LL;typedef unsigned long long ULL;typedef pair<int,int> PII;typedef pair<LL,LL> PLL;typedef vector<PII> VPII;const int INF = 0x3f3f3f3f;const int MOD = 1e9 + 7;const int mod = 100000000;const int maxn = (1<<12) + 10;int dp[15][maxn];int g[15][15],two[15];vector<int>a[15];int n,m;//预处理2的幂次void init(){    two[0] = 1;    for( int i = 1; i < 15; i++ )        two[i] = two[i-1] << 1;}int fun(int x){    int ret = 0;    for( int i = 1; i <= m; i++ ){        ret += (!g[x][i]) * two[m-i];//注意这里是g[x][i]为0 ,与下面的判断放羊是否合法对应    }    return ret;}int main(){    init();    while(~scanf("%d%d",&n,&m)){        cl(a);cl(dp);        for( int i = 1; i <= n; i++ ){            for( int j = 1; j <= m; j++ ){                scanf("%d",g[i]+j);            }        }        int k = 1 << m;        //处理边界的情况        for( int i = 0; i < k; i++ )            dp[0][i] = 1;        a[0].push_back(0);        for( int i = 1; i <= n; i++ ){            int tmp = fun(i);//这行的状态            for( int j = 0; j < k; j++ ){                if(j & (j >> 1))continue;//判断同行是否相邻                if(j & tmp)continue;//判断放羊是否合法                a[i].push_back(j);            }            for( int j = 0; j < a[i].size(); j++ ){                int u = a[i][j];                for( int t = 0; t < a[i-1].size(); t++ ){                    int v = a[i-1][t];                    if(u & v)continue;//判断是否与上一行相邻                    dp[i][u] = (dp[i][u] + dp[i-1][v]) % mod;                }            }        }        int ans = 0;        for( int i = 0; i < k; i++ ){            ans = (ans + dp[n][i]) % mod;        }        printf("%d\n",ans);    }    return 0;}
0 0