PKU/POJ 3264 Corn Fields

  题目出处:http://poj.org/problem?id=3254

  解法: 状态压缩dp

  对每一层分开处理,首先从[0,1<<N)枚举状态,如果没有两片草地相邻,而且和草地不冲突就是合法状态。判断是不是有两片相邻可以这样:j&(j<<1) || j&(j>>1),判断草地不合法:假设草地的状态是j,比如sample里面两行的状态分别是111 和10,如果现在枚举状态是i,则如果i|j==j就是合法,没有占用没有草得地。这样可以优化到0ms。

  然后从上往下递推,如果是第一行,只要状态是合法这个状态下取法就是1,如果是>1行,对上一行每一个状态枚举,如果两个状态不冲突即没有相邻的草地,那么这个状态的取法就加上上一行那个状态的取法。依次类推。结果就是最后一行的各个状态取法的和。

  代码有少量注释。

/*
ID: like_091
PROG: spin
LANG: C++
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <map>
#include <cstring>
#include <string.h>
#include <fstream>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;

const int MAX=(1<<12);
int M, N, t[15][15], first[15];
int state[15][MAX], index[15], sum[15][MAX], max_value;

//获取合法状态
void init(){
    
    int i, j;
    
    for (i=1; i<= M; i++){
        index[i]=0;
        for (j=0; j<max_value; j++){
            //如果存在相邻的1则不能取
            if (j&(j<<1) || j&(j>>1))
                continue;
            //如果和给出的草地不冲突就合法
            if ((first[i]|j)==first[i])
                state[i][index[i]++]=j;
        }
    }
}

int main(){

    int i, j, k;

    while (scanf("%d%d", &M, &N)!=EOF)
    {
        for (i=1; i<= M; i++){
            first[i]=0;
            for (j=1; j<=N; j++){
                scanf("%d", &t[i][j]);
                //草地有无的状态
                if (t[i][j])first[i] += 1<<(j-1);
            }
        }

        max_value=1<<N;

        init();
        memset(sum, 0, sizeof(sum));

        for (i=1; i<=M; i++){
            for (j=0; j < index[i]; j++){
                if (i==1){
                    sum[i][j]=1;
                    continue;
                }
                for (k=0; k<index[i-1]; k++){
                    //如果和上一层冲突则不可以取
                    if (state[i][j]&state[i-1][k])
                        continue;
                    sum[i][j]+=sum[i-1][k];
                    sum[i][j]%=100000000;
                }
            }
        }

        __int64 tot = 0;
        for (i=0; i<index[M]; i++){
            tot += sum[M][i];
            tot %= 100000000;
        }
        cout<<tot<<endl;
    }
    return 0;
}
posted @ 2011-08-23 10:20  like@neu  阅读(175)  评论(0编辑  收藏  举报