uva 519 Puzzle (II)(回溯)


  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.

Input 

The input file consists of blocks of lines. Each block except the last describes one puzzle problem. In the first line of the block there are integers  n  and  m $0 < n, m Ÿ\le 6$  separated by one space. The integers  n m  indicate the number of rows and columns in the puzzle respectively. The description of individual puzzle pieces is in the following  $n \times m$  lines of the block. Each piece is a rectangle 3 centimeters wide and 4 centimeters high with possible juts or cavities in the middle of its sides. For each side of a puzzle piece just one of the following possibilities is true (see picture):

  • there is no jut or cavity on the side, i.e., the side is flat - such sides can be used only on edges of the final picture when assembling the puzzle,
  • there is one jut in the middle of the side,
  • there is one cavity in the middle of the side.


\begin{picture}(2301,2118)(0,-10)\put(585.000,912.000){\arc{450.000}{1.5708}{4.......{\SetFigFont{14}{16.8}{\rmdefault}{\mddefault}{\updefault}jut}}}}}\end{picture} 

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.

Output 

The output file contains the lines corresponding to the blocks in the input file. A line contains  YES  if the corresponding block in the input file describes a puzzle that can be correctly assembled. Otherwise it contains  NO . There is no line in the output file corresponding to the last ``null'' block of the input file.

Sample Input 

3 5
FOOF
FOOI
FOOI
FOOI
FFOI
IOOF
IOOI
IOOI
IOOI
IFOI
IOFF
IOFI
IOFI
IOFI
IFFI
0 0

Sample Output 

YES
题目大意:给出一些拼图的碎片,要求判断是否能组成一个矩形,对于碎片,F表示平面,I表示凸面,O表示凹面,对于矩形,边必须为平, 并且碎片相连这能是以IO形式。

解题思路:1:IO数量要匹配, F要与该出长宽匹配(不匹配直接减掉)

2:在回溯的过程中,每一块拼图的决定是由前一个的right和上一个的bottom决定的,所以读入碎片的时候就将碎片按lift和top分成九类,这样在搜索的时候可以减少搜索量。

(对于边界上的拼图,可以用这样的处理方式,从1行或者1列开始,因为数组在运算的时候要初始化,默认为0,可以将序号为0的编号为FFFF,这样只需要考虑后界和下界)

3:如果有位置没有合适的拼图,可以直接回溯(这是很对有稍难度的回溯题需要用到的)。

#include <stdio.h>
#include <string.h>
#define N 50
#define M 10

int n, m, ok, vis[N];
int list[M][N], cnt[M], map[M][M];
int rec[M][M];
struct puzzle{
    int top;
    int right;
    int bottom;
    int lift;
}block[N];

int change_char(char c){
    if (c == 'F')
	return 0;
    else if (c == 'O')
	return 1;
    else if (c == 'I')
	return 2;
}

bool judge(){
    rec[0][3] = m;
    rec[1][3] = n;
    for (int i = 0; i < 2; i++){
	if (rec[i][0] != rec[3 - i][0] || rec[i][0] != rec[i][3])
	    return false;
//	if (rec[i][1] + rec[i][2] != rec[i][3])
//	    return false;
	for (int j = 1; j <= 2; j++)
	    if (rec[i][j] != rec[3 - i][3 - j])
		return false;
    }
//    printf("!\n");
    return true;
}

void handle(int cur, char str[]){
    int p, q, k, t;
    p = block[cur].top = change_char(str[0]);
    rec[0][p]++;
    k = block[cur].right = change_char(str[1]);
    rec[1][k]++;
    t = block[cur].bottom = change_char(str[2]);
    rec[3][t]++;
    q = block[cur].lift = change_char(str[3]);
    rec[2][q]++;
    list [p * 3 + q][cnt[p * 3 + q]++] = cur;
}

int change_num(int x, int y){
    int k = 0;
    if (x == 2)
	k += 1;
    else if (x == 1)
	k += 2;

    if (y == 2)
	k += 3;
    else if (y == 1)
	k += 6;
    return k;
}

void dfs(int x, int y){
    int cur = change_num(block[map[x][y - 1]].right, block[map[x - 1][y]].bottom);
    for (int i = 0; i < cnt[cur]; i++){
	if (vis[list[cur][i]])  continue;

	if (x == n && y == m){
	    if (block[list[cur][i]].right + block[list[cur][i]].bottom)
		continue;
	    ok = 1;
	    return;
	}
	else if (x == n){
	    if (block[list[cur][i]].right  == 0 || block[list[cur][i]].bottom)
		continue;
	    vis[list[cur][i]] = 1;
	    map[x][y] = list[cur][i];
	    dfs(x, y + 1);
	}
	else if (y == m){
	    if (block[list[cur][i]].right || block[list[cur][i]].bottom == 0)
		continue;
	    vis[list[cur][i]] = 1;
	    map[x][y] = list[cur][i];
	    dfs(x + 1, 1);
	}
	else{
	    if (block[list[cur][i]].right == 0 || block[list[cur][i]].bottom == 0)
		continue;
	    vis[list[cur][i]] = 1;
	    map[x][y] = list[cur][i];
	    dfs(x, y + 1);
	}

	vis[list[cur][i]] = 0;
	if (ok) return;
    }
}

int main(){
    char str[M];
    while (scanf("%d%d", &n, &m), n + m){
	// Init.
	memset(block, 0, sizeof(block));
	memset(list, 0, sizeof(list));
	memset(vis, 0, sizeof(vis));
	memset(cnt, 0, sizeof(cnt));
	memset(map, 0, sizeof(map));
	memset(rec, 0, sizeof(rec));
	ok = 0;

	// Read.
	for (int i = 1; i <= n * m; i++){
	    scanf("%s", str);
	    handle(i, str);
	}

	if (judge())
	    dfs(1, 1);

	printf("%s\n", ok?"YES":"NO");
    }
    return 0;}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值