码迷,mamicode.com
首页 > 其他好文 > 详细

uva519 - Puzzle (II)(回溯)

时间:2014-05-15 08:00:13      阅读:259      评论:0      收藏:0      [点我收藏+]

标签:blog   class   code   c   tar   http   

题目:uva519 - Puzzle (II)


题目大意:给出拼图,要求将给出的拼图拼成 n行m列的矩形,可以输出yes,不行输出no。

解题思路:直接dfs,但是需要剪枝。

1、判断 F 的出现个数是否等于 2 * ( n + m) , 还有IO的个数是否匹配,不匹配就直接剔除,。

2、边界问题要处理,例如第一行第N行,第一列第M列,这些地方的拼图是有要求的,这些边界拼图的的外围都要是F。例如第一行的top要是F,不是F的直接不考虑。(这点导致我TL了N次)

3、相同形状的拼图,在相同一层的dfs里可以不用在考虑了。因为前面出现了一样的但是结果是不行的,所以和他相同的就不需要考虑了,但是这个仅限于同一层dfs里面,因为如果不是同一层,那么可能前面与他相邻的拼图变化了,这样这个形状的拼图可能在这种情况下就是可以的。相同形状的可以用三进制数表示,也可以排序后,直接字符串比较。

4、可以将这些拼图事先分好组,上面为F一组,下面为F的为1组,我这里分了12组。这样查找的时候就可以把范围缩小了。

前三点做到了就可以过了。


代码:(做到四点)

#include <stdio.h>
#include <string.h>

const int N = 50;
const int M = 10;

struct PUZZLE {

	int top;
	int left;
	int bottom;
	int right;
} puzzle[N];

int rec[M][M], vis[N], list[M + 2][N];
char str[M];
int n, m, cnt[M + 2], p_value[N];
bool flag;

int hash (int k) {

	int num;
	num = puzzle[k].top + puzzle[k].left * 3 + puzzle[k].bottom * 9 + puzzle[k].right * 27; 
	return num;
}

int interpret (char ch) {

	if (ch == ‘F‘)
		return 0;
	if (ch == ‘O‘)
		return 1;
	if (ch == ‘I‘)
		return 2;
}

void clasify (int i, int k) {

	if (str[i] == ‘F‘)
		list[i * 3][cnt[i * 3]++] = k;
	else if (str[i] == ‘I‘)
		list[i * 3 + 1][cnt[i * 3 + 1]++] = k;
	else
		list[i * 3 + 2][cnt[i * 3 + 2]++] = k;
}

void handle (int k) {

	for (int i = 0; i < strlen (str); i++) {

		if (i == 0) 
			puzzle[k].top = interpret(str[i]);
		else if (i == 1) 
			puzzle[k].right = interpret(str[i]);	
		else if (i == 2) 
			puzzle[k].bottom = interpret(str[i]);	
		else
			puzzle[k].left = interpret(str[i]);

		clasify (i, k); 
	}
}

void dfs (int x, int y) {

	if (flag)
		return;
	if (x > n) {

		flag = 1;
		return ;
	}
	int k, map[M * M];
	memset (map , 0, sizeof (map));
	if (x == 1)
		k = 0;
	else if (x == n)
		k = 6;
	else if (y == 1)
		k = 9;
	else if (y == m)
		k = 3;
	else  {

		if (puzzle[rec[x - 1][y]].bottom == 0) 
			k = 0;	
		else if (puzzle[rec[x - 1][y]].bottom == 1)
			k = 1;
		else if (puzzle[rec[x - 1][y]].bottom == 2)
			k = 2;
		else if (puzzle[rec[x][y - 1]].right == 0)
			k = 9;
		else if (puzzle[rec[x][y - 1]].right == 1)
			k = 10;
		else if (puzzle[rec[x][y - 1]].right == 2)
			k = 11;
	}
	for (int i = 0; i < cnt[k]; i++) {

		if (map[p_value[list[k][i]]])
			continue;
		if (vis[list[k][i]])
			continue;
		if (!((puzzle[list[k][i]].left + puzzle[rec[x][y - 1]].right) % 3) && !((puzzle[list[k][i]].top + puzzle[rec[x - 1][y]].bottom) % 3)) {

			rec[x][y] = list[k][i];
			vis[list[k][i]] = 1;
			if (y + 1 > m) 
				dfs (x + 1, 1);
			else
				dfs (x, y + 1);
			if (flag)
				return;
			vis[list[k][i]] = 0;
			map[p_value[list[k][i]]] = 1;
		}
	}
}

void init () {

	flag = 0;
	memset (cnt, 0, sizeof (cnt));
	memset (rec, 0, sizeof (rec));
	memset (vis, 0, sizeof (vis));
	memset (list, 0, sizeof (list));
	puzzle[0].top = puzzle[0].left = puzzle[0].bottom = puzzle[0].right = 0;

}

int main () {

	while (scanf ("%d%d", &n, &m) , n || m) {

		init ();	
		for (int i = 1 ; i <= n * m; i++) {

			scanf ("%s", str);
			handle(i);
		}

		int n1 = 0, n2 = 0;
		for (int i = 0; i < 4; i++) {

			n1 += cnt[i * 3 + 1];
			n2 += cnt[i * 3 + 2];
		}

		if (cnt[0] == m && n1 == n2 && cnt[3] == n && cnt[6] == m && cnt[9] == n) { 

			for (int i = 1; i <= n * m; i++)  
				p_value[i] = hash(i);
			dfs (1, 1);
		}

		printf ("%s\n", flag == 1?"YES":"NO");
	}
	return 0;
}
代码:(做到三点)

#include <stdio.h>
#include <string.h>

const int N = 50;
const int M = 10;

struct PUZZLE {

	int top;
	int left;
	int bottom;
	int right;
} puzzle[N];

int rec[M][M], vis[N];
char str[M];
int n, m, p_value[N];
bool flag;
int c1, c2, c0;

int hash (int k) {

	int num;
	num = puzzle[k].top + puzzle[k].left * 3 + puzzle[k].bottom * 9 + puzzle[k].right * 27; 
	return num;
}

int interpret (char ch) {

	if (ch == ‘F‘)
		return 0;
	if (ch == ‘O‘)
		return 1;
	if (ch == ‘I‘)
		return 2;
}


void handle (int k) {

	for (int i = 0; i < strlen(str); i++) {

		if (i == 0) 
			puzzle[k].top = interpret(str[i]);
		else if (i == 1) 
			puzzle[k].right = interpret(str[i]);	
		else if (i == 2) 
			puzzle[k].bottom = interpret(str[i]);	
		else
			puzzle[k].left = interpret(str[i]);

		if (str[i] == ‘F‘)
			c0++;
		else if (str[i] == ‘O‘)
			c2++;
		else
			c1++;
	}
}

void dfs (int x, int y) {

	if (flag)
		return;
	if (x > n) {

		flag = 1;
		return ;
	}
	int k, map[M * M];
	memset (map , 0, sizeof (map));
	for (int i = 1; i <= n * m; i++) {

		if (x == 1 && puzzle[i].top != 0)
			continue;
		if (x == n && puzzle[i].bottom != 0)
			continue;
		if (y == 1 && puzzle[i].left != 0)
			continue;
		if (y == m && puzzle[i].right != 0)
			continue;
		if (map[p_value[i]])
			continue;
		if (vis[i])
			continue;
		if (!((puzzle[i].left + puzzle[rec[x][y - 1]].right) % 3) && !((puzzle[i].top + puzzle[rec[x - 1][y]].bottom) % 3)) {

			rec[x][y] = i;
			vis[i] = 1;
			if (y + 1 > m) 
				dfs (x + 1, 1);
			else
				dfs (x, y + 1);
			if (flag)
				return;
			vis[i] = 0;
			map[p_value[i]] = 1;
		}
	}
}

void init () {

	flag = 0;
	memset (rec, 0, sizeof (rec));
	memset (vis, 0, sizeof (vis));
	c1 = c2 = c0 = 0;
	puzzle[0].top = puzzle[0].left = puzzle[0].bottom = puzzle[0].right = 0;

}

int main () {

	while (scanf ("%d%d", &n, &m) , n || m) {

		init ();	
		for (int i = 1 ; i <= n * m; i++) {

			scanf ("%s", str);
			handle(i);
		}
		if (c1 == c2 &&  c0 == 2 * (m + n)) { 

			for (int i = 1; i <= n * m; i++)  
				p_value[i] = hash(i);
			dfs (1, 1);
		}

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



uva519 - Puzzle (II)(回溯),布布扣,bubuko.com

uva519 - Puzzle (II)(回溯)

标签:blog   class   code   c   tar   http   

原文地址:http://blog.csdn.net/u012997373/article/details/25839911

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!