POJ 3254 Corn Fields (状态压缩)
刚开始的思路是 把0-2^x的 所有状态枚举, 然后找符合条件的, 但是 发现 当12*12 时 1的数量x 超过64 这是个庞大的数字, 跟本就没法枚举;
想到用状态压缩, 但是 怎么压缩才行 ?
作为这是状态压缩入门题, 感觉 废了好大力气;
【思路】
把每一行 0/1状态 转换成 十进制的数, 每一行看成一个整体, 进行压缩,
【第一步】
先提前处理 相邻两项不符合条件的 例如 001 和 011 这样的就不符合 (违背相邻两项不种植条件)
【第二步】
为了可以找到符合条件的, 在进行输入时 处理, 把 输入的 010 进行 取反 得到的是 101 目的是 & =0; 找到当前行 满足条件的
例如 示例 第二行 010, 那么只有 010 和 000 才能放在这 010 取反为 101 , 101 & 010 =0 101 & 000 =0 这是符合条件的
【第三步】
找到当前行符合条件的, 那么进行筛选, 筛选出 既不能与前一行 相邻, 又不能与 之前到找的 重复 ;
找到后 累加到当前行中, 用dp【】【】 存储
dp【i】【j】 代表 第 i 行 状态 j 时 符合条件数目;
方程 dp【i】【j】 = Sigma dp 【i-1】【k】 k代表所有符合的 项
【代码】
//#include <bits/stdc++.h> #include <iostream> #include <stdio.h> #include <algorithm> #include <cmath> #include <math.h> #include <cstring> #include <string> #include <queue> #include <stack> #include <stdlib.h> #include <list> #include <map> #include <set> #include <bitset> #include <vector> #define mem(a,b) memset(a,b,sizeof(a)) #define findx(x) lower_bound(b+1,b+1+bn,x)-b #define FIN freopen("input.txt","r",stdin) #define FOUT freopen("output.txt","w",stdout) #define S1(n) scanf("%d",&n) #define SL1(n) scanf("%I64d",&n) #define S2(n,m) scanf("%d%d",&n,&m) #define SL2(n,m) scanf("%I64d%I64d",&n,&m) #define Pr(n) printf("%d\n",n) #define lson rt << 1, l, mid #define rson rt << 1|1, mid + 1, r #define mem(a,b) memset(a,b,sizeof(a)) typedef long long ll; const int INF=0x3f3f3f3f; const ll MOD=1e8; const int MAXN=1e5+5; const int N=1000; ll qpow(ll x,ll n){ll res=1;for(;n;n>>=1){if(n&1)res=(res*x);x=(x*x);}return res;} using namespace std; int dp[N][N]; int cur[MAXN]; int state[MAXN]; int cot; int n,m; void init() { int bits= 1<<m; cot=0; for(int i=0;i<bits;i++) { if( (i&(i<<1))==0 )// 去除相邻的两项 state[++cot]=i; } } int main() { while(~scanf("%d %d",&n,&m)) { init();//提前处理所以不相邻的数据 for(int i=1;i<=n;i++) { int x; for(int j=1;j<=m;j++) { scanf("%d",&x); if(x==0) { cur[i]+= (1<< (m-j)); // 取反 目的是 将 后面的重复项去掉, 例如 010 取反为 101 & 010 =0 } } } mem(dp,0); for(int i=1;i<=cot;i++) { if( (state[i]&cur[1]) ==0)// 边界状态 dp[1][i]=1; } /* for(int i=1;i<=cot;i++) { printf("%d | %d\n",state[i],cur[i]); }*/ for(int i=2;i<=n;i++)// 从第二行开始 { for(int j=1;j<=cot;j++) { if( (state[j]&cur[i])==0 ) //符合条件 当前行 { for(int k=1;k<=cot;k++) { if( ((state[k]&cur[i-1])==0) && ((state[k]&state[j])==0 ) )// 并且不与前一行重复,找到的两个值一样 { //printf("%d***\n",state[k]); dp[i][j]= (dp[i][j]+ dp[i-1][k]) %MOD; } } } } } int ans=0; for(int i=1;i<=cot;i++) ans = (ans+dp[n][i])% MOD; printf("%d\n",ans); } } /* 12 12 1 0 1 0 1 0 1 0 1 1 1 1 0 0 1 0 0 1 0 0 0 1 1 1 1 0 0 0 1 1 0 1 0 0 0 1 1 0 1 1 1 0 1 0 1 0 1 0 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 1 0 1 0 1 1 1 0 1 0 1 1 0 1 0 1 0 0 0 0 1 0 1 0 1 0 1 0 0 1 0 0 0 1 0 1 0 1 0 0 0 1 0 1 0 1 0 1 1 0 1 0 1 */
岂曰无衣?与子同袍。王于兴师,修我戈矛。与子同仇!
岂曰无衣?与子同泽。王于兴师,修我矛戟。与子偕作!
岂曰无衣?与子同裳。王于兴师,修我甲兵。与子偕行!