这道题看似很麻烦,但看明白了可以直接dfs求解。按理说,这题的复杂度应该挺高的,但不知为什么不用什么剪枝就能过,可能数据太水了。
用一个数组Adjacent[][]记录下每个面的相邻面编号,在dfs时,枚举每一个tile,然后有五种放置方法,判断每一种是否合理,若合理则进入下一个循环,当12个tile都放完则输出,否则无解。
这道题搁置了很长时间,之前觉得这么直接暴力模拟可能超时,不敢写。后来没什么办法,就写写试试,结果连样例都出不来,当时在对程序没有认真检查的情况下,去看解题报告,发现都说这题很简单,不用什么剪枝。看了他们的思路,感觉思路是一样的,为什么我的出不出来结果呢?好好的分析之后发现,中间标记位置的时候,面的标号和tile的编号我弄混了,改过来之后就过了……没想到这道题就这么容易可做……
做题的时候不要被题表面的复杂迷惑了,读题后要认真分析,然后再判断题能不能做,代码能力很是很差……
程序代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
bool vis[13];
int tile[13][6], ans[13][2];
int Adjacent[15][6] = { 0, 0, 0, 0, 0, 0,
0, 2, 3, 4, 5, 6,
0, 1, 6, 7 ,11, 3,
0, 1, 2, 11, 10, 4,
0, 1, 3, 10, 9, 5,
0, 1, 4, 9, 8, 6,
0, 1, 5, 8, 7, 2,
0, 8, 12, 11, 2, 6,
0, 9, 12, 7, 6, 5,
0, 10, 12, 8, 5, 4,
0, 11, 12, 9, 4, 3,
0, 7, 12, 10, 3, 2,
0, 7, 8, 9, 10, 11
};
int mod(int v)
{
return (v + 5) % 5;
}
bool dfs(int cur, int mp[][13])
{
if(cur > 12) return true;
int mp1[13][13];
for(int i = 1; i <= 12; i++){
if(!vis[i]){
for(int j = 0, k; j < 5; j++){ //枚举面=tile的5个位置
memcpy(mp1, mp, sizeof(mp1));
for(k = 0; k < 5; k++){
if(mp1[cur][Adjacent[cur][k + 1]] == -1){ //判断是否合法
mp1[cur][Adjacent[cur][k + 1]] = mp1[Adjacent[cur][k + 1]][cur] = tile[i][mod(j + k)];
}else if(mp1[cur][Adjacent[cur][k + 1]] != tile[i][mod(j + k)])
break;
}
if(k >= 5){
vis[i] = true;
ans[cur][0] = i; ans[cur][1] = Adjacent[cur][mod(5 - j) + 1]; //记录当前放的tile和参考边所对应的面
if(dfs(cur + 1, mp1)) return true;
vis[i] = false;
}
}
}
}
return false;
}
int main()
{
//freopen("input.txt", "r", stdin);
int mp[13][13];
for(int i = 1; i <= 12; i++)
for(int j = 0; j < 5; j++)
scanf("%d", &tile[i][j]);
memset(mp, -1, sizeof(mp));
memset(vis, 0, sizeof(vis));
if(dfs(1, mp)){
for(int i = 1; i <= 12; i++){
printf("%d %d\n", ans[i][0], ans[i][1]);
}
}else printf("-1\n");
return 0;
}