状态压缩二 (hiho 1048)

来源:互联网 发布:足彩数据分析app软件 编辑:程序博客网 时间:2024/06/04 18:04

题意:给出一个N*M的矩形格子,用2*1的块去填满块的方案数。

           2<=N<=1000, 3<=m<=5

思路:由于M比较小,可以用位对其进行记录,矩形内1*1的格子的状态有

           横着的开始,横着的结尾,竖着的开始,竖着的结尾,所以用0,1,2,3

           来分别进行表示,这样用一个2bit即可。

           为了加速,先把不可能的一些状态进行剔除,把中间的可能转移状态一次计算好,

           在状态转移的时候直接拿来用就比较省时间。



#include<cstdio>#include<iostream>#include<cstring>#include<queue>#include<string>#include<vector>using namespace std;int dp[1111][1111];int n,nstate,m,q;int state[1111];vector<int> v[1111];const int M=1000000007;int get(int x,int n){return (x&(3<<(n<<1)))>>(n<<1);}bool isFrist(int x){for (int i=0;i<m;i++){int temp=get(x,i);if (temp==0) i++;else if (temp==2) continue;else return false;}return true;}bool isEnd(int x){for (int i=0;i<m;i++){int temp=get(x,i);if (temp==0) i++;else if (temp==3) continue;else return false;}return true;}bool isok(int x){for (int i=0;i<m;i++){int temp=get(x,i);if (temp==0){if (temp==m-1) return false;if (get(x,i+1)!=1) return false;i++;}else if (temp==1) return false;}return true;}bool isok2(int x,int y){for (int i=0;i<m;i++){//cout<<i<<' '<<get(x,i)<<' '<<get(y,i)<<endl;int temp=get(x,i);if (temp==2){if (get(y,i)!=3) return false;}else if (get(y,i)==3) return false;}return true;}int main(){freopen("in","r",stdin);cin>>n>>m;nstate=1<<(m<<1);q=0;for (int i=0;i<nstate;i++) if (isok(i)) state[q++]=i;for (int i=0;i<q;i++) if (isFrist(state[i])) dp[0][state[i]]=1;for (int i=0;i<q;i++) for (int j=0;j<q;j++) if (isok2(state[i],state[j]))  v[i].push_back(state[j]);  for (int i=0;i<n-1;i++) for (int j=0;j<q;j++) if (dp[i][state[j]]) { //cout<<state[j]<<endl; for (int k=0;k<v[j].size();k++) dp[i+1][v[j][k]]=(dp[i+1][v[j][k]]+dp[i][state[j]])%M; }int ans=0;for (int i=0;i<nstate;i++) if (isEnd(i)) ans=(ans+dp[n-1][i])%M;cout<<ans<<endl;//cout<<endl;//cout<<isok2(68,68)<<endl;//for (int i=0;i<nstate;i++) if (dp[0][i]) cout<<i<<' '<<v[i].size()<<endl;}


0 0
原创粉丝点击