UVA - 519 Puzzle (II) 回溯+剪枝

题目大意: 给出N*M的矩阵,有N*M个拼图板,问能否把N*M的矩阵填满

解题思路:剪枝+回溯

1.F的数量要是2*(M+N),I和O的数量要想等

2.同层递归的话,相同的就跳过

3.第一行的up要为F,最后一行的bottom要为F,第一列的left要为F,最后一列的right要为F

4.判断条件,当前这块的left和左边的right相加的和%3要为0,当前这块的UP和上面的bottom的和%3也要为0(F的值为0,I的值为,0的值为2)

#include<cstdio>
#include<cstdlib>
#include<cstring>

struct puzzle{
	int top;
	int right;
	int bottom;
	int left;
}p[100];

int row,col;
int co,cf,ci;
int flag;
int vis[100];
int rec[100][100];
int value[100];

int change(char c) {
	if(c == 'F') {
		cf++;
		return 0;
	}
	if(c == 'O') {
		co++;
		return 1;
	}
	if(c == 'I') {
		ci++;
		return 2;
	}
}

void handle(char str[6],int i) {

	p[i].top = change(str[0]);
	p[i].right = change(str[1]);
	p[i].bottom = change(str[2]);
	p[i].left = change(str[3]);	
}

int hash(int i) {
	int temp =  p[i].top + p[i].right * 3 + p[i].bottom * 9 + p[i].left * 27;
	return temp;
}

void dfs(int r, int c) {
	if(flag )
		return ;
	if(r > row) {
		flag = 1;
		return ;	
	}
	int map[100];
	memset(map,0,sizeof(map));
	for(int i = 1 ; i <= row * col; i++)  {
		if(r == 1 && p[i].top != 0)
			continue;
		if(c == 1 && p[i].left != 0)
			continue;
		if(r == row  && p[i].bottom != 0)
			continue;
		if(c == col  && p[i].right != 0)
			continue;
		if(vis[i])
			continue;
		if(map[value[i]])
			continue;

		if( !( (p[i].left + p[rec[r][c-1]].right) % 3) && !( (p[i].top + p[rec[r-1][c]].bottom) %3)) {
			rec[r][c] = i;
			vis[i] = 1;
			if(c == col)
				dfs(r+1,1);
			else
				dfs(r,c+1);
			if(flag)
				return ;
			vis[i] = 0;
			map[value[i]] = 1;
		}
	}
}

void init() {
	memset(rec,0,sizeof(rec));
	memset(vis,0,sizeof(vis));
	flag = 0;
	cf = ci = co = 0;
	p[0].top = p[0].left = p[0].right = p[0].bottom = 0;
}

int main() {
	while(scanf("%d%d\n",&row,&col) != EOF && row+col) {

		char temp[6];
		init();
		for(int i = 1; i <= row*col; i++) {
			scanf("%s",temp);
			handle(temp,i);
		}


		if(cf == 2*(row+col) && ci == co) {
			for(int i = 1; i <= row*col; i++)
				value[i] = hash(i);
			dfs(1,1);
		}
		if(flag)
			printf("YES\n");
		else
			printf("NO\n");
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值