POJ 3254 Corn Fields (状压DP,轮廓线DP)

题意:

  有一个n*m的矩阵(0<n,m<=12),有部分的格子可种草,有部分不可种,问有多少种不同的种草方案(完全不种也可以算1种,对答案取模后输出)?

思路:

  明显的状压DP啦,只是怎样压缩状态?跟轮廓线DP一样,按格子为单位来设计状态,一个状态只需要表示到其上方和左方的格子,所以最多只需要保存min(n,m)个01状态就行了(可以尝试旋转一下矩阵),最多需要12位。用哈希表来做会比较快吧,不用去考虑无效的状态,比如出现相邻两个1。

  1 //#include <bits/stdc++.h>
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cmath>
  6 #include <map>
  7 #include <algorithm>
  8 #include <vector>
  9 #include <iostream>
 10 #define pii pair<int,int>
 11 #define INF 0x7f3f3f3f
 12 #define LL long long
 13 #define ULL unsigned long long
 14 using namespace std;
 15 const double PI  = acos(-1.0);
 16 const int N=13;
 17 const int M=100000000;
 18 int g[N][N];
 19 struct Hash_Map
 20 {
 21     static const int mod=1237;
 22     static const int N=10000;
 23     int head[mod];      //桶指针
 24     int next[N];        //记录链的信息
 25     int status[N];      //状态
 26     int  value[N];       //状态对应的DP值。
 27     int size;
 28     void clear()    //清除哈希表中的状态
 29     {
 30         memset(head, -1, sizeof(head));
 31         size = 0;
 32     }
 33
 34     void insert(int st, int val)  //插入状态st的值为val
 35     {
 36         int h = st%mod;
 37         for(int i=head[h]; i!=-1; i=next[i])
 38         {
 39             if(status[i] == st) //这个状态已经存在,累加进去。
 40             {
 41                 value[i] += val;
 42                 value[i]%=M;
 43                 return ;
 44             }
 45         }
 46         status[size]= st;           //找不到状态st,则插入st。
 47         value[size] = val;
 48         next[size] = head[h] ;      //新插入的元素在队头
 49         head[h] = size++;
 50     }
 51 }hashmap[2];
 52
 53 int cal(int n,int m)
 54 {
 55     int cur=0, mod=(1<<m-1)-1;
 56     hashmap[cur].clear();
 57     hashmap[0].insert(0,1);
 58     for(int i=1; i<=n; i++)
 59     {
 60         for(int j=1; j<=m; j++)
 61         {
 62             cur^=1;
 63             hashmap[cur].clear();
 64             for(int k=0; k<hashmap[cur^1].size; k++)
 65             {
 66                 int s=hashmap[cur^1].status[k];
 67                 int v=hashmap[cur^1].value[k];
 68                 int t=(s&mod)<<1;   //去掉最高位
 69                 hashmap[cur].insert(t,v);       //不放
 70                 if(g[i][j])
 71                 {
 72                     if( s&(1<<m-1) )    continue;
 73                     if( j!=1 && (s&1) ) continue;   //不能放
 74                     hashmap[cur].insert(t^1,v);
 75                 }
 76             }
 77         }
 78     }
 79     int ans=0;
 80     for(int k=0; k<hashmap[cur].size; k++)
 81     {
 82         ans+=hashmap[cur].value[k];
 83         ans%=M;
 84     }
 85     return ans;
 86 }
 87
 88
 89 int main()
 90 {
 91     //freopen("input.txt","r",stdin);
 92     int n, m;
 93     while(~scanf("%d%d",&n,&m))
 94     {
 95         for(int i=1; i<=n; i++)
 96             for(int j=1; j<=m; j++)
 97                 scanf("%d",&g[i][j]);
 98         printf("%d\n",cal(n,m));
 99     }
100     return 0;
101 }

AC代码

时间: 2024-12-16 10:21:13

POJ 3254 Corn Fields (状压DP,轮廓线DP)的相关文章

POJ 3254 Corn Fields 状压DP

链接:http://poj.org/problem?id=3254 题意:一块M*N的田地,每小块地大小是1*1,可以种植物的标记为1,不可以种植物的标记为0,并且相邻的两块地不可以同时种植物.问题是有多少种不同的种植方案(所有地都不种也是一种种植方案) 思路:这是第一道状压DP题,从第一行更新到最后一行,每一行用一个N位的二进制数来表示该行的状态1表示该位置种了植物,0表示该位置没种植物.因为每块地只对相邻的土地能否种植有所影响,所以每一行的状态可以用前一行的状态递推得到. 资料:http:/

POJ 3254 Corn Fields (状压DP+滚动数组)

题目地址:POJ 3254 状压水题. 先预处理出每行所有可能出现的情况.然后可以用vector存起来. 然后先处理出第一行所有的情况.然后再从第二行开始不断与上一行进行状态转移,状态转移很简单就不说了. 最后统计出最后一行的个数和就可以了. 代码如下; #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #

poj 3254 Corn Fields 状压dp入门

// poj3254 状压dp入门 // dp[i][S]表示前i行第i行状态为S时放牧的情况 // S为十进制的二进制数形式如5为101表示第一列和第三列放牧的方法数 // 首先dp[0][S]合法的话就是1 // 状态转移方程为dp[i][S] = sigma(dp[i-1][V])(S与V是合法状态) // 最后的结果就是dp[n][S](S为所有的合法状态) // // 刚开始十分傻x的dp[0][S]置为get(S),...get(S)是其中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 /* ***********************

POJ 1684 Corn Fields(状压dp)

描述 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 can't be

POJ 3254 Corn Fields 【状压DP】

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

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 (C++/Java)

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

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'为符合条