HDU

来源:互联网 发布:云计算行业发展 编辑:程序博客网 时间:2024/06/03 21:58

Tetris Comes Back


Problem Description
Working in corporation is toilsome and rest is important. In leisure time, WisKey like to play Tetris. The Tetris game in board is N*5, and there are 8 kinds of blocks.
  Look that, red mean the area can’t be place. Other colors mean different kinds of blocks. If I give you C grey blocks (the 1st kind), and other infinite color blocks, Can you fulfil the board without any blocks overlap.
 

Input
Each case will contain two integers N (1<=N<=1000) and C (0<=C<=100). 
N*5 grid follow it. The ‘1’ represent red area, it can’t be place. The ‘0’ represent normal area.
Process cases to end of file.

 

Output
If you can full of the Tetris, print “YES”, otherwise, print “NO”.
 

Sample Input
1 1000001 1001001 1010104 110000001011001000000
 

Sample Output
YESYESNOYES
 


题意:给你C个1*1的棋子,和无数个如图的2345678的棋子,问你能否拼成N*5大小的棋盘。其中棋盘有一些地方已经被填了。


解题思路:有点小激动,第一次靠自己做出了一道状压DP题。题目和SGU - 131 Hardwood floor (状压DP)是一类题目,但是这题多了许多条件。我们可以用dp[i][num][state]表示能否达到在第1~i-1行填满的情况下,用了num个1*1,第i行状态为state的状态。我们遍历每一行,每种num,每种状态,通过深搜来尝试放各种棋子,要判断好每种棋子能不能放。详看代码注释。




#include<iostream>#include<deque>#include<memory.h>#include<stdio.h>#include<map>#include<string>#include<algorithm>#include<vector>#include<math.h>#include<stack>#include<queue>#include<set>#define INF 1<<29using namespace std;int dp[1005][105][1<<6];int sta[1005];//记录每一行的初始状态int h,c;// 当前行的初始状态,当前行的状态,下一行的状态,当前判断到第几列,当前是第几行,当前用了多少个1*1,初始状态是多少个1*1void dfs(int prestate,int nowstate,int nextstate,int n,int cnt,int cnum,int fnum){    //不能大于规定数量    if(cnum>c)        return;    //当前行填完了    if(n>=5){        dp[cnt+1][cnum][nextstate]|=dp[cnt][fnum][prestate]&1;//状态转移        return;    }        //如果当前行的第n列被填了,就跳过    if(((1<<n)&nowstate)!=0){        dfs(prestate,nowstate,nextstate,n+1,cnt,cnum,fnum);//下一个        return;    }    //用1*1去填    dfs(prestate,nowstate|(1<<n),nextstate,n+1,cnt,cnum+1,fnum);    //用 | 去填    if((nextstate&(1<<n))==0){        dfs(prestate,nowstate|(1<<n),nextstate|(1<<n),n+1,cnt,cnum,fnum);    }    //用  |_  去填    if(n!=0)        if((nextstate&(1<<n))==0&&(nextstate&(1<<(n-1)))==0)            dfs(prestate,nowstate|(1<<n),nextstate|(1<<n)|(1<<(n-1)),n+1,cnt,cnum,fnum);    //用  _|  去填    if(n<4)        if((nextstate&(1<<n))==0&&(nextstate&(1<<(n+1)))==0)            dfs(prestate,nowstate|(1<<n),nextstate|(1<<n)|(1<<(n+1)),n+1,cnt,cnum,fnum);        if(n<4&&((1<<(n+1))&nowstate)==0){        dfs(prestate,nowstate|(1<<n)|(1<<(n+1)),nextstate,n+2,cnt,cnum,fnum);//打横放 ——        if((nextstate&(1<<n))==0)            dfs(prestate,nowstate|(1<<n)|(1<<(n+1)),nextstate|(1<<n),n+2,cnt,cnum,fnum);//这样放 -|        if((nextstate&(1<<(n+1)))==0)            dfs(prestate,nowstate|(1<<n)|(1<<(n+1)),nextstate|(1<<(n+1)),n+2,cnt,cnum,fnum);//这样放  |-        //放2*2        if((nextstate&(1<<n))==0&&(nextstate&(1<<(n+1)))==0)            dfs(prestate,nowstate|(1<<n)|(1<<(n+1)),nextstate|(1<<n)|(1<<(n+1)),n+2,cnt,cnum,fnum);    }}int main(){    while(~scanf("%d%d",&h,&c)){        memset(dp,0,sizeof(dp));        memset(sta,0,sizeof(sta));        dp[1][0][0]=1;        //初始化每行的状态        char str[10];        int sss=0;        for(int i=1;i<=h;i++){            scanf("%s",str);            sss=0;            for(int i=0;i<5;i++){                if(str[i]=='1'){                    sss|=(1<<(5-i-1));                }            }            sta[i]=sss;        }        int state=1<<5;        //遍历所有状态        for(int i=1;i<=h;i++){            for(int k=0;k<=c;k++)                if(dp[i][k][0]==1)                    dp[i][k][sta[i]]=1;            for(int j=0;j<state;j++){                j|=sta[i];                                for(int k=0;k<=c;k++)                    dfs(j,j,sta[i+1],0,i,k,k);            }        }                bool flag=0;        for(int k=0;k<=c;k++)            if(dp[h+1][k][0])                flag=1;        if(flag)            printf("YES\n");        else            printf("NO\n");    }    return 0;}