POJ-3254-Corn Fields-DP+状态压缩(入门题)

题目链接:http://poj.org/problem?id=3254

题目意思:给你一个n*m的牧场,叫你带牛去吃草,其中0代表没有草不可以放牧,1代表有草可以放牧。而且两头牛不可以相邻,叫你求所有可能的放牧方案。

思路:这是个状态压缩的基础题,刚学状态压缩的可以用这个题目来理解状态压缩;(如果是刚学DP我建议理解题意后先粗略的看一下代码后再边看代码边看我的思路,效果更佳)

1、题目告诉我们两头牛不能相邻,那么我们就可以枚举出每一行的所有情况,并且用数组st保存起来;怎么枚举每一种情况呢,题目说明不放也是一种方案,所以我们从0开始放,这里就可以很巧妙的用二进制来枚举,对于每一个位置,我们都可以选择放或者不放,用0表示不放,用1表示放。所以共有2^m(m为每一行的列数,用1<<m表示)中情况,并且枚举完情况之后,我们用judge1来判断是否存在相邻1的情况,剔除之,保存不存在相邻为1的情况;其中用位运算可以直接判断是否含有相邻的1;(x<<1&x)返回为1说明存在相邻的1,0则反之;位运算思想我相信接触多了就会很自然很习惯的使用;

2、题目还告诉我们只有在有草的地方才能够放牧,这就又给我们多了一个限制条件,这样可以给我们剔除很多方案,降低数据的庞大;那么我们也先将题目给的土地状态用一个数组Map保存起来。这里我们同样用二进制转换成十进制保存,但是这里我们需要注意的就是我们保存土地的相反数,比如说:101(1为可以放牧的),我们保存成010,为什么要这样保存呢??这是为了方便后面判断是否会和该行的状态相矛盾;即假设我当前的状态是010,判断这种状态是否会和土地状态相冲突,我们之前保存的就可以直接与土地状态&运算一下,如果返回的是1说明就相冲突了,因为我们Map数组的1是保存的不能放的状态;当土地不能放牧的时候用1<<(j-1)移位来保存该行的土地状态;

3、明白了这两点我想这个题目就很清楚了;我们先把第一行的情况都处理一下;然后从第二行开始枚举每一行事先枚举保存的的各种符合情况的状态st[i];判断是否与土地状态相矛盾;如果不矛盾,我们就判定是否与上一行的各种状态相矛盾,如果不矛盾,那么该行的这种状态的方案数就加上上一行符合情况的状态的方案数,这就是状态转移方程;dp[i][j]+=dp[i-1][f],(0<=f<k);

4、最后统计第n行各种状态的方案数总和就可以了;(当然这道题必要的基础就是对位运算要有较好的理解);

关于位运算,大家可以简单的看一下百度百科:http://baike.baidu.com/link?url=TnwY0uf6_qCLW1M9GFys6L-lgzMf4kmE23UsI7Uw67mHl_HFrY8eVwgnutKnOwRcHK-xRXf9dpI58UYnvqxp5a

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<queue>
#include<map>
#include<cmath>
#include<stack>
#include<set>
#include<vector>
#include<algorithm>
#define LL long long
#define inf 1<<30
using namespace std;
const int N=13;
const int M=1<<N;
const int mod=100000000;
int n,m,x;
int st[M];      //  存每一行的状态;
int Map[M];      //  存取反后给出的地的状态;
int dp[N][M];       //  用于存第i行状态为j的时候可以放牛的种数;
bool judge1(int x)      //  判断左右是否存在相邻的1;
{
    return (x&(x<<1));  //  如果不为0那就说明有相邻的1;
}
bool judge2(int i,int x)    //  判断该行的状态是否与土地的状态相矛盾;
{
    return (Map[i]&st[x]);
}
int main()
{
    while(~scanf("%d%d",&n,&m)){
        memset(dp,0,sizeof(dp));
        memset(st,0,sizeof(st));
        memset(Map,0,sizeof(Map));
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%d",&x);
                if(x==0){          //   不合法状态;
                    Map[i]+=(1<<(j-1));     //  通过位移存入Map[i],表示该行不合法状态;
                }
            }
        }
        int k=0;
        for(int i=0;i<(1<<m);i++){
            if(!judge1(i)) st[k++]=i;   //  保存不存在相邻为1的状态数;
        }
        for(int i=0;i<k;i++){       //  初始化第一行各种状态下的总数;
            if(!(judge2(1,i))) dp[1][i]=1;
        }
        for(int i=2;i<=n;i++){          //  枚举每行k种符合不含相邻1的情况;
            for(int j=0;j<k;j++){
                if(judge2(i,j)) continue;   //  剔除不符合情况与土地状态矛盾的情况;
                for(int f=0;f<k;f++){
                    if(judge2(i-1,f)) continue;    //   剪枝,去除上一行不符合情况;
                    if(!(st[j]&st[f])){     //  j状态是否与上一行矛盾;
                        dp[i][j]+=dp[i-1][f];   //  意思就是这一行放这种状态的种数等于上一行可以放的各种状态的种数之和;
                    }
                }
            }
        }
        int ans=0;
        for(int i=0;i<k;i++){   //  所以很显然左后一行的各种状态之和就是所有合法状态的方案数;
            ans+=dp[n][i];
            ans%=mod;
        }
        printf("%d\n",ans);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-29 07:52:06

POJ-3254-Corn Fields-DP+状态压缩(入门题)的相关文章

POJ 3254 Corn Fields DP 状态压缩 入门

Description Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and

poj 3254 Corn Fields ,状态压缩DP

题目链接 题意: 一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻.问有多少种放牛方案(一头牛都不放也是一种方案) state[i] 表示对于一行,保证不相邻的方案 状态:dp[i][ state[j] ]  在状态为state[j]时,到第i行符合条件的可以放牛的方案数 状态转移:dp[i][ state[j] ] =Sigma dp[i-1][state'] (state'为符合条

poj 3254 Corn Fields(状态压缩dp)

Description Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and

POJ 3254 Corn Fields 状态压缩DP (C++/Java)

http://poj.org/problem?id=3254 题目大意: 一个农民有n行m列的地方,每个格子用1代表可以种草地,而0不可以.放牛只能在有草地的,但是相邻的草地不能同时放牛, 问总共有多少种方法. 思路: 状态压缩的DP. 可以用二进制数字来表示放牧情况并判断该状态是否满足条件. 这题的限制条件有两个: 1.草地限制. 2.相邻限制. 对于草地限制,因为输入的时候1是可以种草地的. 以"11110"草地分析,就只有最后一个是不可以种草的.取反后得00001  .(为啥取反

POJ 3254 Corn Fields //入门状压dp

Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7578   Accepted: 4045 Description Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yumm

POJ 3254 Corn Fields 【状压DP】

[题目大意]一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻.问有多少种放牛方案(一头牛都不放也是一种方案) [解析]根据题意,把每一行的状态用二进制的数表示,0代表不在这块放牛,1表示在这一块放牛.首先很容易看到,每一行的状态要符合牧场的硬件条件,即牛必须放在能放牧的方格上.这样就能排除一些状态.另外,牛与牛之间不能相邻,这样就要求每一行中不能存在两个相邻的1,这样也能排除很多状态.

[ An Ac a Day ^_^ ] POJ 3254 Corn Fields 状压dp

题意: 有一块n*m的土地 0代表不肥沃不可以放牛 1代表肥沃可以放牛 且相邻的草地不能同时放牛 问最多有多少种放牛的方法并对1e8取模 思路: 典型的状压dp 能状态压缩 能状态转移 能状态压缩的题的特点就是只有两种状态 所以用0 1表示两种状态 用位运算判断是否符合条件 然后将前一行的合理状态转移到后一行 最后统计最后一行的状态 dp[i][j]代表第i行以第j种状态放牛时有多少种不同的状态 (c++的语言特性是 封装 继承 多态~) 1 /* ***********************

状态压缩dp入门 第一题 POJ 3254 Corn Fields

Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 6460   Accepted: 3436 Description Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yumm

POJ 3254. Corn Fields 状态压缩DP (入门级)

Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9806   Accepted: 5185 Description Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yumm

POJ 3254 Corn Fields 状态压缩DP

题目链接:http://poj.org/problem?id=3254 思路:状态压缩DP,状态方程为dp[i][j] += (dp[i-1][k]) code: #include <stdio.h> #include <string.h> #define N 500 const int MOD = 100000000; int dp[15][N],ant[N],n,m,k,map[15]; bool ok(int x) { if(x&(x<<1))return