题目链接:
题目类型: 隐式图搜索
原题:
There are black and white knights on a 5 by 5 chessboard. There are twelve of each color, and there is one square that is empty. At any time, a knight can move into an empty square as long as it moves like a knight in normal chess (what else did you expect?).
Given an initial position of the board, the question is: what is the minimum number of moves in which we can reach the final position which is:
Input
First line of the input file contains an integer N (N<14) that indicates how many sets of inputs are there. The description of each set is given below:
Each set consists of five lines; each line represents one row of a chessboard. The positions occupied by white knights are marked by 0 and the positions occupied by black knights are marked by 1. The space corresponds to the empty square on board.
There is no blank line between the two sets of input.
The first set of the sample input below corresponds to this configuration:
Output
For each set your task is to find the minimum number of moves leading from the starting input configuration to the final one. If that number is bigger than 10, then output one line stating
Unsolvable in less than 11 move(s).
otherwise output one line stating
Solvable innmove(s).
wheren<= 10.
The output for each set is produced in a single line as shown in the sample output.
2
01011
110 1
01110
01010
00100
10110
01 11
10111
01001
00000
Unsolvable in less than 11 move(s).
Solvable in 7 move(s).
题目大意:
一个5*5的棋盘上放着数量相同的白色和黑色的马, 只留一个空格。任意空格周围的的马,只要它可以跳到空格(和中国象棋一样走“日”字,八个方向,且不会被挡到),就可跳到空格上。
给定一个初始状态的棋盘, 然后要求计算出在11步之内能否把棋盘走成目标棋盘一样的状态。
分析与总结:
这题和八数码问题相似,只是走法不同,以及棋盘尺寸变成5*5的棋盘。
这题的关键在于状态判重, 因为有25格,所以八数码的那个哈希函数是不能用了的,需要换一个处理字符串的哈希函数。
按照网上的一篇分析文章,BKDRHash哈希函数有着很良好的性能,于是我便选用了这个哈希函数。
其它的过程基本上和八数码问题差不多。
/* * UVA 10422 - Knights in FEN * http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=1363 * Time: 0.196s (UVA) * Athor: D_Double * */ #include<iostream> #include<cstring> #include<cstdio> #include<map> #define MAXN 5000000 using namespace std; map<string, bool>vis; int dir[8][2] = {{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2}}; typedef char State[5][5]; State que[MAXN], start, goal={{'1','1','1','1','1'}, {'0','1','1','1','1'}, {'0','0',' ','1','1'}, {'0','0','0','0','1'}, {'0','0','0','0','0'}}; int step[MAXN], ans; const int HASHSIZE = 3000000; int head[HASHSIZE], next[MAXN]; void init_lookup_table() { memset(head, 0, sizeof(head)); } inline int BKDRHash(State &s) // 字符串哈希函数 { unsigned int seed = 131; // 31 131 1313 13131 131313 etc.. unsigned int hash = 0; for(int i=0; i<5; ++i){ for(int j=0; j<5; ++j) hash = hash * seed + s[i][j]; } return (hash & 0x7FFFFFFF) % HASHSIZE; } inline int try_to_insert(int s){ int h = BKDRHash(que[s]); int u = head[h]; while(u){ if(memcmp(que[u], que[s], sizeof(que[s]))==0) return 0; u = next[u]; } next[s] = head[h]; head[h] = s; return 1; } void bfs(){ init_lookup_table(); int front=0, rear=1; memcpy(que[0], start, sizeof(start)); step[0] = 0; while(front < rear){ State &s = que[front]; if(step[front] > 10) { ans = -1; return; } if(memcmp(goal, s, sizeof(s))==0){ ans = step[front]; return; } // 获取空格的位置 int x,y; bool flag=false; for(int i=0; i<5; ++i){ for(int j=0; j<5; ++j)if(s[i][j]==' '){ x=i, y=j; flag=true; break; } if(flag) break; } for(int i=0; i<8; ++i){ int dx = x+dir[i][0]; int dy = y+dir[i][1]; if(dx>=0 && dx<5 && dy>=0 && dy<5){ State &t = que[rear]; memcpy(t, s, sizeof(s)); t[dx][dy] = s[x][y]; t[x][y] = s[dx][dy]; step[rear] = step[front]+1; if(try_to_insert(rear)) rear++; } } front++; } ans = -1; } int main(){ int T; char str[20]; scanf("%d%*c", &T); while(T--){ for(int i=0; i<5; ++i){ gets(str); for(int j=0; j<5; ++j) start[i][j] = str[j]; } bfs(); if(ans!=-1) printf("Solvable in %d move(s).\n", ans); else printf("Unsolvable in less than 11 move(s).\n"); } return 0; }
—— 生命的意义,在于赋予它意义。