POJ 3254 Corn Fields (状压DP,轮廓线DP)
2015-10-06 20:36
381 查看
题意:
有一个n*m的矩阵(0<n,m<=12),有部分的格子可种草,有部分不可种,问有多少种不同的种草方案(完全不种也可以算1种,对答案取模后输出)?
思路:
明显的状压DP啦,只是怎样压缩状态?跟轮廓线DP一样,按格子为单位来设计状态,一个状态只需要表示到其上方和左方的格子,所以最多只需要保存min(n,m)个01状态就行了(可以尝试旋转一下矩阵),最多需要12位。用哈希表来做会比较快吧,不用去考虑无效的状态,比如出现相邻两个1。
AC代码
有一个n*m的矩阵(0<n,m<=12),有部分的格子可种草,有部分不可种,问有多少种不同的种草方案(完全不种也可以算1种,对答案取模后输出)?
思路:
明显的状压DP啦,只是怎样压缩状态?跟轮廓线DP一样,按格子为单位来设计状态,一个状态只需要表示到其上方和左方的格子,所以最多只需要保存min(n,m)个01状态就行了(可以尝试旋转一下矩阵),最多需要12位。用哈希表来做会比较快吧,不用去考虑无效的状态,比如出现相邻两个1。
//#include <bits/stdc++.h> #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <map> #include <algorithm> #include <vector> #include <iostream> #define pii pair<int,int> #define INF 0x7f3f3f3f #define LL long long #define ULL unsigned long long using namespace std; const double PI = acos(-1.0); const int N=13; const int M=100000000; int g ; struct Hash_Map { static const int mod=1237; static const int N=10000; int head[mod]; //桶指针 int next ; //记录链的信息 int status ; //状态 int value ; //状态对应的DP值。 int size; void clear() //清除哈希表中的状态 { memset(head, -1, sizeof(head)); size = 0; } void insert(int st, int val) //插入状态st的值为val { int h = st%mod; for(int i=head[h]; i!=-1; i=next[i]) { if(status[i] == st) //这个状态已经存在,累加进去。 { value[i] += val; value[i]%=M; return ; } } status[size]= st; //找不到状态st,则插入st。 value[size] = val; next[size] = head[h] ; //新插入的元素在队头 head[h] = size++; } }hashmap[2]; int cal(int n,int m) { int cur=0, mod=(1<<m-1)-1; hashmap[cur].clear(); hashmap[0].insert(0,1); for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { cur^=1; hashmap[cur].clear(); for(int k=0; k<hashmap[cur^1].size; k++) { int s=hashmap[cur^1].status[k]; int v=hashmap[cur^1].value[k]; int t=(s&mod)<<1; //去掉最高位 hashmap[cur].insert(t,v); //不放 if(g[i][j]) { if( s&(1<<m-1) ) continue; if( j!=1 && (s&1) ) continue; //不能放 hashmap[cur].insert(t^1,v); } } } } int ans=0; for(int k=0; k<hashmap[cur].size; k++) { ans+=hashmap[cur].value[k]; ans%=M; } return ans; } int main() { //freopen("input.txt","r",stdin); int n, m; while(~scanf("%d%d",&n,&m)) { for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) scanf("%d",&g[i][j]); printf("%d\n",cal(n,m)); } return 0; }
AC代码
相关文章推荐
- 事件与事件处理程序
- 鞍点
- C#学习之多线程开发技术(二)
- 树——线段树
- Java实现双向链表
- PHP的错误异常信息是否输出
- iOS:多线程NSThread的详细使用
- TeX排版记录 多行长公式 括号 对齐 问题
- 解档与归档
- UI_UITableView编辑
- java的hashtable与hashMap 的讲解
- micro-template改造
- bzoj1041
- RouterOS(ROS)安装
- 【bzoj1856】【Scoi2010】【字符串】
- bzoj1041
- leetcode:Sort List(一个链表的归并排序)
- 个人博客作业 #3
- 英语语法 限定词
- Big Event in HDU 背包