题目大意:给出拼图,要求将给出的拼图拼成 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;
}