POJ 2441 Arrange the Bulls && POJ 3254 Corn Fields 状压DP入门

来源:互联网 发布:拍淘宝衣服的模特要求 编辑:程序博客网 时间:2024/06/14 08:48

传送门:POJ2441

题意:将n头牛分到m个牛栏里,每头牛都有自己喜欢的牛栏,每个牛栏只能放一头牛,问共有多少种分配方案。

思路:由于n和m都很小,状压搞一搞就好了,dp[i]表示m个牛栏的状态为i的分配方案(将i转化为2进制,1表示有牛,0表示没有牛)

__builtin_popcount(k)
返回k的二进制中有多少个1

代码:

#include<stdio.h>#include<iostream>#include<vector>#define ll long long#define pb push_back#define fi first#define se second#define pi acos(-1)#define inf 0x3f3f3f3f#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1#define rep(i,x,n) for(int i=x;i<n;i++)#define per(i,n,x) for(int i=n;i>=x;i--)using namespace std;typedef pair<int,int>P;const int MAXN=100010;int gcd(int a,int b){return b?gcd(b,a%b):a;}vector<int> p[30];int dp[1 << 21]; int main(){int n, m;cin >> n >> m;if(m < n) {cout << 0 << endl;return 0;}int t, x;for(int i = 0; i < n; i++){scanf("%d", &t);while(t--){scanf("%d", &x);p[i].pb(--x);}}dp[0] = 1;for(int i = 0; i < n; i++){for(int j = 0; j < p[i].size(); j++){t = p[i][j];for(int k = (1 << m) - 1; k >= 0; k--){if(__builtin_popcount(k) == i)//一开始忘判断这个转移条件了,一直错{if(k & 1 << t) continue;dp[k | 1 << t] += dp[k];} }}}int ans = 0;for(int i = 0; i < (1 << m); i++){if(__builtin_popcount(i) == n) ans += dp[i]; } cout << ans << endl; return 0;}


传送门:POJ3254

题意:给出一个M*N的矩阵,元素为0表示这个地方不能种玉米,为1表示这个地方能种玉米,现在规定所种的玉米不能相邻,问一共有多少种种植方法。

思路:

和上个题差不多,将矩阵的一行压成一个状态,转移的时候枚举当前行的状态和上一行的状态进行转移,再判断一下是否满足题意就行了。

代码:

#include<stdio.h>#include<iostream>#define ll long long#define pb push_back#define fi first#define se second#define pi acos(-1)#define inf 0x3f3f3f3f#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1#define rep(i,x,n) for(int i=x;i<n;i++)#define per(i,n,x) for(int i=n;i>=x;i--)using namespace std;typedef pair<int,int>P;const int MAXN=100010;const int mod = 100000000;int gcd(int a,int b){return b?gcd(b,a%b):a;}bool is[15][15];int dp[2][1 << 13];int main(){int n, m;cin >> n >> m;for(int i = 0; i < n; i++)for(int j = 0; j < m; j++)cin >> is[i][j];bool flag;for(int i = 0; i < (1 << m); i++){flag = 1;for(int j = 0; j < m; j++){if(is[0][j] == 0 && (i >> j) & 1) flag = 0;if(i >> j & 1){if(j < m - 1 && (i >> (j + 1) & 1)) flag = 0;if(j > 0 &&(i >> (j - 1) & 1)) flag = 0; } }dp[0][i] = flag;}int up = (1 << m), e = 1;for(int i = 1; i < n; i++){for(int j = 0; j < up; j++){for(int k = 0; k < up; k++){flag = 1;for(int id = 0; id < m; id++){if(is[i][id] == 0 && ((k >> id) & 1)) flag = 0;if(((k >> id) & 1) && ((j >> id) & 1)) flag = 0;if(k >> id & 1){if(id < m - 1 && (k >> (id + 1) & 1)) flag = 0;if(id > 0 &&(k >> (id - 1) & 1)) flag = 0;}if(flag == 0) break;}if(flag)dp[e][k] += dp[e ^ 1][j], dp[e][k] %= mod;}}e ^= 1;for(int j = 0; j < up; j++)//一开始没清空,快给我wa哭了dp[e][j] = 0;}e ^= 1;int ans = 0;for(int i = 0; i < up; i++)ans += dp[e][i], ans %= mod;cout << ans << endl; return 0;}

 看大佬们博客学到了更快的方法,先预处理出所有可能的转移状态,即一行中没有两两相邻的状态,同时将每一行田地的初始状态也压成一个数字,这样比较的时候就不用循环比较了,直接&一下就好,写起来很简便,速度也快。

代码:

#include<stdio.h>#include<iostream>#include<string.h>#define ll long long#define pb push_back#define fi first#define se second#define pi acos(-1)#define inf 0x3f3f3f3f#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1#define rep(i,x,n) for(int i=x;i<n;i++)#define per(i,n,x) for(int i=n;i>=x;i--)using namespace std;typedef pair<int,int>P;const int MAXN=100010;const int mod = 100000000;int gcd(int a,int b){return b?gcd(b,a%b):a;}int dp[2][1 << 13];int status[1 << 13];int field[13];int main(){int n, m;while(cin >> n >> m){memset(dp, 0, sizeof(dp));int t;for(int i = 0; i < n; i++){field[i] = 0;for(int j = 0; j < m; j++){cin >> t;if(!t)field[i] += 1 << j;}}int cnt = 0, e = 1;for(int i = 0; i < (1 << m); i++)if(!(i & i << 1))//判断相邻两位是否同为1 status[cnt++] = i;for(int i = 0; i < cnt; i++){if(status[i] & field[0]) continue;dp[0][i] = 1;}for(int i = 1; i < n; i++){for(int j = 0; j < cnt; j++){dp[e][j] = 0;if(field[i] & status[j]) continue;for(int k = 0; k < cnt; k++){if(status[k] & field[i - 1]) continue;if(status[j] & status[k]) continue;dp[e][j] += dp[e ^ 1][k], dp[e][j] %= mod;}}e ^= 1; } e ^= 1;int ans = 0;for(int i = 0; i < cnt; i++)ans += dp[e][i], ans %= mod;cout << ans << endl;} return 0;}



原创粉丝点击