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.
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.
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 1 00000 1 1 00100 1 1 01010 4 1 10000 00101 10010 00000
Sample Output
YES YES NO YES
题意:给你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<<29
using namespace std;
int dp[1005][105][1<<6];
int sta[1005];//记录每一行的初始状态
int h,c;
// 当前行的初始状态,当前行的状态,下一行的状态,当前判断到第几列,当前是第几行,当前用了多少个1*1,初始状态是多少个1*1
void 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;
}