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;
}
浙公网安备 33010602011771号