POJ 3254 Corn Fields(状压DP入门)

来源:互联网 发布:浙江省中医院知乎 编辑:程序博客网 时间:2024/05/24 11:15

题意:一个m*n(m, n <= 12)矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,

求两个相邻的方格不能同时放牛,即牛与牛不能相邻。问有多少种放牛方案(一头牛都不放也是一种方案)


思路:可以看代码中的注释。转移方程:dp[i][sta] = ∑(dp[i-1][sta']) (sta‘为与sta不冲突的状态)


带注释代码:

#include <cstdio>#include <cstring>using namespace std;#define mod 100000000int M,N,top = 0;//top表示每行最多的状态数int state[600],num[110];  //state存放每行所有的可行状态(即没有相邻的状态//int dp[20][600];//dp[i][j]:对于前i行数据,每行有前j种可能状态时的解int cur[20];//cur[i]表示的是第i行整行的情况inline bool ok(int x){//判断状态x是否可行   if(x&x<<1)return false;//若存在相邻两个格子都为1,则该状态不可行   return true;}void init(){//遍历所有可能的状态   top = 0;   int total = 1 << N; //遍历状态的上界   for(int i = 0; i < total; ++i){       if(ok(i))state[++top] = i;   }}inline bool fit(int x,int k){ //判断状态x 与第k行的实际状态的逆是否有‘重合’   if(x&cur[k])return false; //若有重合,(即x不符合要求)   return true;  //若没有,则可行}int main(){    while(scanf("%d%d",&M,&N)!= EOF){       init();       memset(dp,0,sizeof(dp));       for(int i = 1; i <= M; ++i){           cur[i] = 0;           int num;           for(int j = 1; j <= N; ++j){  //输入时就要按位来存储,cur[i]表示的是第i行整行的情况,每次改变该数字的二进制表示的一位                scanf("%d",&num);  //表示第i行第j列的情况(0或1)               if(num == 0) //若该格为0   cur[i] +=(1<<(j-1)); //则将该位置为1(注意要以相反方式存储,即1表示不可放牧           }       }       for(int i = 1;i <= top;i++){           if(fit(state[i],1)){  //判断所有可能状态与第一行的实际状态的逆是否有重合                dp[1][i] = 1;  //若第1行的状态与第i种可行状态吻合,则dp[1][i]记为1           }          }   /*   状态转移过程中,dp[i][k] =Sigma dp[i-1][j] (j为符合条件的所有状态)*/       for(int i = 2; i <= M; ++i){  //i索引第2行到第M行           for(int k = 1; k <= top; ++k){ //该循环针对所有可能的状态,找出一组与第i行相符的state[k]                if(!fit(state[k],i))continue; //判断是否符合第i行实际情况                for(int j = 1; j <= top ;++j){ //找到state[k]后,再找一组与第i-1行符合,且与第i行(state[])不冲突的状态state[j]                   if(!fit(state[j],i-1))continue;  //判断是否符合第i-1行实际情况                   if(state[k]&state[j])continue;  //判断是否与第i行冲突                   dp[i][k] = (dp[i][k] +dp[i-1][j])%mod;  //若以上皆可通过,则将'j'累加到‘k'上                }           }       }       int ans = 0;       for(int i = 1; i <= top; ++i){ //累加最后一行所有可能状态的值,即得最终结果!!!泥马写注释累死我了终于写完了!           ans = (ans + dp[M][i])%mod;       }       printf("%d\n",ans);   }}

#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int maxn = 13;const int mod = 1e8;int state[1<<maxn], dp[maxn][1<<maxn];int cur[maxn], m, n, top;bool ok(int x){    return !(x&x<<1);}void init(){    top = 0;    int total = 1<<n;    for(int i = 0; i < total; i++)        if(ok(i))            state[top++] = i;}bool fit(int x, int k){    return !(x&cur[k]);}int main(void){    while(cin >> m >> n)    {        init();        memset(dp, 0, sizeof(dp));        for(int i = 1; i <= m; i++)        {            cur[i] = 0;            int x;            for(int j = 1; j <= n; j++)            {                scanf("%d", &x);                if(!x)                    cur[i] += 1<<(j-1);            }        }        for(int i = 0; i < top; i++)            if(fit(state[i], 1))                dp[1][i] = 1;        for(int i = 2; i <= m; i++)            for(int k = 0; k < top; k++)            {                if(!fit(state[k], i)) continue;                for(int j = 0; j < top; j++)                {                    if(!fit(state[j], i-1)) continue;                    if(state[k]&state[j]) continue;                    dp[i][k] = (dp[i][k]+dp[i-1][j])%mod;                }            }        int ans = 0;        for(int i = 0; i < top; i++)            ans = (ans+dp[m][i])%mod;        printf("%d\n", ans);    }    return 0;}




原创粉丝点击