题目大意:给出拼图,要求将给出的拼图拼成 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
原文地址:http://blog.csdn.net/u012997373/article/details/25839911