题目地址:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=460
题目描述:
Puzzle (II) |
Little Barborka has just started to learn how to solve a picture puzzle. She has started with a small one containing 15 pieces. Her daddy tries to solve the puzzle too. To make it a little bit harder for himself, he has turned all puzzle pieces upside down so that he cannot see pictures on the pieces. Now he is looking for a solution of the puzzle. Normally the solution should exist but he is not sure whether Barborka has not replaced some pieces of the puzzle by pieces of another similar puzzle. Help him and write a program which reads a description of a set of puzzle pieces and decides whether it is possible to assembly the pieces into a rectangle with given side lengths or not.
As is usual, two pieces can be placed side by side only if one has a jut and the other has a cavity on corresponding sides. We will denote the flat sides by F, the sides with juts by O and the sides with cavities by I. Each piece is described by four letters characterizing its top, right, bottom, and left side. To make the task easier the pieces can be used only as they are described i.e. they cannot be turned.
After each block there is an empty line. The last block consists of just one line containing 0 0, i.e. two zeros separated by one space.
3 5 FOOF FOOI FOOI FOOI FFOI IOOF IOOI IOOI IOOI IFOI IOFF IOFI IOFI IOFI IFFI 0 0
YES题意:
拼图,小碎片有凹有平有凸,让其拼成一个边缘无凹凸的矩形。
题解:
DFS+剪枝,注意小碎片的长宽不一样,拼图时长宽要做到一一对应。
剪枝:
1、F的数量要是2*(m+n),即等于矩形的周长,IO的数量要想等,可以更细化小碎片长边的IO和短边的IO要分别相等。
2、关键剪枝,由于碎片是可以有重复构型的,这样dfs会有许多重复碎片而导致冗余路径,所以保证该位置次碎片不可填即预示所有相同构形的碎片都不可填,这里可以对碎片事先分类,即该类碎片不可填 立即换到下一类碎片 而不是下一个碎片。
注意:
此题在2013-11-28的时候rejudge了,当初我做的时候,本来使用一维数组存储矩形来做 是WA的,结果换成二维数组存储矩形 然后dfs却AC了,真是百思不得其解,好在后来rejudge了,还是有点坑,浪费3天的时间生成各种数据测试WA程序。
代码:
代码一(rejudge后AC,一维存储矩形)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; int n=0,m=0;//n is the row,m is the column typedef struct kind { /* data */ char piestr[4+5];//all string is same,we need the len++ or len-- to control the string count int len; kind() { memset(piestr,'\0',sizeof(piestr)); len=0; } }kind,*kindlink; kind piekind[100+5];//the kind piece lib int cntkind=0;//the kind of the count char puzzle[100+5][4+5]={'\0'};//the puzzle container string newpuzzle[10][10];//new puzzle container int cntpie=0;//the ocunt of the piece int peripie=0;//perimeter of the piece 's side int flag=0;//yes or no /*initialize the lib*/ int InitLib() { int i=0; for(i=0;i<=cntkind-1;i++) { piekind[i].len=0; } cntkind=0; return(0); } /*insert the piece to the piece lib*/ int insertlib(char GStr[]) { int i=0,j=0; int findflag=0; for(i=0;i<=cntkind-1;i++) { //find the same kind if(strcmp(GStr,piekind[i].piestr)==0) { findflag=1; piekind[i].len++; break; } } if(!findflag)//not find it ,we will build the new kind for the peikind lib { strcpy(piekind[cntkind].piestr,GStr); piekind[cntkind].len++; cntkind++; } return(0); } /*match the touch,the I&O is match \0&* is match, the if 's order is important*/ bool MatchSide(char a,char b) { if(a=='\0'||b=='\0') return(true); //a!='\0' and b!='\0' if(a=='F'||b=='F') return(false); //a!='\0'and'F' b!='\0'and'F' if(a==b) return(false); return(true); } /*judge the string is fit for place it to the position cur*/ bool IsFit(char piestr[],int cur) { //get the first row or mid row or last row,one dimension to the two dimension coordinate int row=cur/m; int col=cur%m; char top=piestr[0],right=piestr[1],bottom=piestr[2],left=piestr[3]; //F problem //row if(row==0)//first row,this structure note that the n=1 or m=1 's case { if(!(top=='F'))//the first row must have this condition return(false); } if(row==n-1)//last row { if(!(bottom=='F')) return(false); } if(row>0&&row<n-1)//mid row { if(!(top!='F'&&bottom!='F')) return(false); } //col if(col==0)//first one { if(!(left=='F')) return(false); } if(col==m-1)//last one { if(!(right=='F')) return(false); } if(col>0&&col<m-1)//mid one { if(!(left!='F'&&right!='F')) return(false); } //I O match problem //get the neighbour piece int leftcur=row*m+(col-1); char lefttop='\0',leftright='\0',leftbottom='\0',leftleft='\0';//init '\0' if(col>=1) { lefttop=puzzle[leftcur][0];leftright=puzzle[leftcur][1];leftbottom=puzzle[leftcur][2];leftleft=puzzle[leftcur][3]; if(!MatchSide(leftright,left))//cur and the leftcur touch match return(false); } int topcur=(row-1)*m+col; char toptop='\0',topright='\0',topbottom='\0',topleft='\0';//init '\0' if(row>=1) {//this {} must be added , because the following line is multiple sentence` toptop=puzzle[topcur][0];topright=puzzle[topcur][1];topbottom=puzzle[topcur][2];topleft=puzzle[topcur][3]; if(!MatchSide(topbottom,top))//cur and top cur touch match return(false); } //the I&O is match \0&* match return(true); } /*fill this piece to the puzzle*/ int FillPie(int ind,int cur) { strcpy(puzzle[cur],piekind[ind].piestr); piekind[ind].len--; return(0); } /*unfill this piece from the puzzle*/ int UnFillPie(int ind,int cur) { piekind[ind].len++; return(0); } /*DFS the piece*/ int DFS(int cur) { if(flag) { return(0); } if(cur==cntpie) { flag=1; return(0); } else { int i=0; for(i=0;i<=cntkind-1;i++) { if(piekind[i].len>0&&IsFit(piekind[i].piestr,cur)) { FillPie(i,cur); DFS(cur+1); if(flag) { return(0); } UnFillPie(i,cur); } } } return(0); } /*for test*/ int test() { return(0); } /*main process*/ int MainProc() { while(scanf("%d%d",&n,&m)!=EOF&&(n+m)>0) { //init int i=0,j=0; cntpie=n*m; peripie=m+n+m+n; int cntF=0,cntI=0,cntO=0; flag=0; InitLib(); for(i=0;i<=cntpie-1;i++) { char GStr[4+5]={'\0'}; scanf("%s",GStr); //get the count of F I O j=0; while(GStr[j]!='\0') { switch(GStr[j]) { case 'F': cntF++; break; case 'I': cntI++; break; case 'O': cntO++; break; } j++; } //put into the piekind lib,update the piekind and the cntkind insertlib(GStr); } //prune the count of F and I with O if(cntF==peripie&&cntI==cntO) { //NewDFS(0,0);//DFS the piece DFS(0); } if(flag) { printf("YES\n"); } else { printf("NO\n"); } } return(0); } int main(int argc, char const *argv[]) { /* code */ MainProc(); return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; int n=0,m=0;//n is the row,m is the column typedef struct kind { /* data */ char piestr[4+5];//all string is same,we need the len++ or len-- to control the string count int len; kind() { memset(piestr,'\0',sizeof(piestr)); len=0; } }kind,*kindlink; kind piekind[100+5];//the kind piece lib int cntkind=0;//the kind of the count char puzzle[100+5][4+5]={'\0'};//the puzzle container string newpuzzle[10][10];//new puzzle container int cntpie=0;//the ocunt of the piece int peripie=0;//perimeter of the piece 's side int flag=0;//yes or no /*initialize the lib*/ int InitLib() { int i=0; for(i=0;i<=cntkind-1;i++) { piekind[i].len=0; } cntkind=0; return(0); } /*insert the piece to the piece lib*/ int insertlib(char GStr[]) { int i=0,j=0; int findflag=0; for(i=0;i<=cntkind-1;i++) { //find the same kind if(strcmp(GStr,piekind[i].piestr)==0) { findflag=1; piekind[i].len++; break; } } if(!findflag)//not find it ,we will build the new kind for the peikind lib { strcpy(piekind[cntkind].piestr,GStr); piekind[cntkind].len++; cntkind++; } return(0); } /*match the touch,the I&O is match \0&* is match, the if 's order is important*/ bool MatchSide(char a,char b) { if(a=='\0'||b=='\0') return(true); //a!='\0' and b!='\0' if(a=='F'||b=='F') return(false); //a!='\0'and'F' b!='\0'and'F' if(a==b) return(false); return(true); } /*IsFit reload*/ bool IsFit(char piestr[],int x,int y) { //get the first row or mid row or last row,one dimension to the two dimension coordinate int row=x; int col=y; char top=piestr[0],right=piestr[1],bottom=piestr[2],left=piestr[3]; //F problem //row if(row==0)//first row,this structure note that the n=1 or m=1 's case { if(!(top=='F'))//the first row must have this condition return(false); } if(row==n-1)//last row { if(!(bottom=='F')) return(false); } if(row>0&&row<n-1)//mid row { if(!(top!='F'&&bottom!='F')) return(false); } //col if(col==0)//first one { if(!(left=='F')) return(false); } if(col==m-1)//last one { if(!(right=='F')) return(false); } if(col>0&&col<m-1)//mid one { if(!(left!='F'&&right!='F')) return(false); } //I O match problem //get the neighbour piece char lefttop='\0',leftright='\0',leftbottom='\0',leftleft='\0';//init '\0' if(col>=1) { lefttop=newpuzzle[row][col-1][0];leftright=newpuzzle[row][col-1][1];leftbottom=newpuzzle[row][col-1][2];newpuzzle[row][col-1][3]; if(!MatchSide(leftright,left))//cur and the leftcur touch match return(false); } char toptop='\0',topright='\0',topbottom='\0',topleft='\0';//init '\0' if(row>=1) {//this {} must be added , because the following line is multiple sentence` toptop=newpuzzle[row-1][col][0];topright=newpuzzle[row-1][col][1];topbottom=newpuzzle[row-1][col][2];topleft=newpuzzle[row-1][col][3]; if(!MatchSide(topbottom,top))//cur and top cur touch match return(false); } //the I&O is match \0&* match return(true); } /*new DFS*/ int NewDFS(int x,int y) { if(flag) { return(0); } if(x>=n) { flag=1; return(0); } if(y>=m) { NewDFS(x+1,0); } else { int i=0; for(i=0;i<=cntkind-1;i++) { if(piekind[i].len>0&&IsFit(piekind[i].piestr,x,y)) { piekind[i].len--; newpuzzle[x][y]=piekind[i].piestr; NewDFS(x,y+1); if(flag) { return(0); } piekind[i].len++; } } } return(0); } /*for test*/ int test() { return(0); } /*main process*/ int MainProc() { while(scanf("%d%d",&n,&m)!=EOF&&(n+m)>0) { //init int i=0,j=0; cntpie=n*m; peripie=m+n+m+n; int cntF=0,cntI=0,cntO=0; flag=0; InitLib(); for(i=0;i<=cntpie-1;i++) { char GStr[4+5]={'\0'}; scanf("%s",GStr); //get the count of F I O j=0; while(GStr[j]!='\0') { switch(GStr[j]) { case 'F': cntF++; break; case 'I': cntI++; break; case 'O': cntO++; break; } j++; } //put into the piekind lib,update the piekind and the cntkind insertlib(GStr); } //prune the count of F and I with O if(cntF==peripie&&cntI==cntO) { NewDFS(0,0);//DFS the piece } if(flag) { printf("YES\n"); } else { printf("NO\n"); } } return(0); } int main(int argc, char const *argv[]) { /* code */ MainProc(); return 0; }