HDU 1400 && POJ 2411

来源:互联网 发布:台湾朝阳科技大学 知乎 编辑:程序博客网 时间:2024/05/03 23:46



题意:求用1*2的矩阵填满n*m的矩阵的方法有多少种;


题解:


状压DP,,,,


1*2的矩阵要么橫着放,要么竖着放,把

橫着放的矩阵标记为 

1 1

竖着放的矩阵标记为

假如现在我们在铺砖 位置(i, j), 并且假设之前的位置已经铺设好的了,在这个位置,我们的选择:

1. 不用铺砖了,可能在(i-1, j)的时刻已经被竖着铺上了,然后考虑的是(i, j+1)

2. 横铺砖,将(i, j+1)也铺上了,然后考虑的是(i, j+2)

3. 竖着铺砖,(将i,j)和(i+1,j)铺上一个竖立的转头。


这样处理到最后一行必定得到一行1.

如:




#include<iostream>using namespace std;long long dp[15][2050];int n,m,num;bool Isok(int x)//符合1*2摆放的{int i=0;{    while(i<m){   if(x&(1<<i))   {   if((x&(1<<(i+1)))==0) return false;        if(i==m-1) return false;   i+=2;   }   else    {      i++;   }}}return true;}bool Istrue(int x,int y){    int i=0;while(i<m){    if((x&(1<<i))==0){    if((y&(1<<i))==0)//若y的第j位置为0,则x的第j位置必须是1(竖着的状态),否则返回falsereturn false;i++;}else{    if((y&(1<<i))==0)i++;else if(i==m-1||!((x&(1<<(i+1)))&&(y&(1<<(i+1)))))//如果x,y的第i位置为1,则x,y的i+1的位置也要为1,(横着的状态)。return false;else i+=2;}}return true;}int main(){while(scanf("%d%d",&n,&m)){    int i,j,k;if(m>n) swap(m,n);if(n==0&&m==0) break;if(n*m%2!=0) {  cout<<"0"<<endl;  continue;}num=(1<<m);memset(dp,0,sizeof(dp));for(i=0;i<num;i++)if(Isok(i))dp[0][i]=1;//处理第一行初始可行的状态int ans=0;for(i=1;i<n;i++){for(j=0;j<num;j++)//第i行的第j状态{for(k=0;k<num;k++)//i-1的k状态{if(Istrue(j,k))dp[i][j]+=dp[i-1][k];}}}//for(i=0;i<num;i++)//if(dp[n-1][state[i]]) ans+=dp[n-1][state[i]];cout<<dp[n-1][(1<<m)-1]<<endl;}return 0;}/*1 21 31 42 22 32 42 114 110 0*/


0 0
原创粉丝点击