10422 - Knights in FEN(迭代深度搜索)

题目:10422 - Knights in FEN


题目大意:5 * 5的棋盘上摆好了旗子,旗子是按照马走日的规则来的,问能在十步之内将起始的棋盘变成题目所给的棋盘那样吗?可以输出最少步数,不可以就输出不行。


解题思路:这题之前我是想着用bfs,但是那个时候判重的时候没有想到用STL的map,用哈希不太会,直接开数组判重又太大了,用map<string, int>来记录一个棋盘的状态(之前没有想到),后来看了别人的代码,发现可以用迭代dfs,因为这题只需要判断十步内的情况,这样题目所给的时间还算是有余的,因为迭代dfs()比广搜要慢。

思路是:每次限定一个深度来进行深搜,这样就不会死循环,并且这个深度就是要求的步数。每限制一个深度就需要重头开始搜索一遍,这样比较花时间。但是节约了空间。这题的马只能跳到空格上,所以就重空格开始,按照规则构造棋盘,注意每次返回的时候都要返回原来的那个状态。这里代码里还参照了别人的剪枝的思想,提前判断一下现在这个状态要到达目标状态最少还要走多少步,如果现在的步数加上还要走的步数超过限定的深度,就可以直接返回了。还有要注意可以不移动就到达目标状态的情况。


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

const int M = 5;
int t, deep;
char finish[M][M];
const char init[M][M] = {{'1', '1', '1', '1', '1'},{'0', '1', '1', '1', '1'},{'0', '0', ' ', '1', '1'},{'0', '0', '0', '0', '1'},{'0', '0', '0', '0', '0'}};
const int dx[] = {-2, -1, 1, 2, 2, 1, -1, -2};
const int dy[] = {-1, -2, -2, -1, 1, 2, 2, 1};

int cut() {

	int sum = 0;
	for(int i =0; i < M; i++)
		for(int j = 0; j < M; j++)
			sum += (finish[i][j] != init[i][j]);
		return sum / 2;		
}

int dfs(int d, int x, int y) {

	if(d > deep)
		return 0;
	if(memcmp(finish, init, sizeof(init)) == 0)
		return 1;
	if(d + cut() > deep)
		return 0;
	for(int i = 0; i < 8; i++){

		int nx = x + dx[i];
		int ny = y + dy[i];
		if(nx >= 0 && nx < M && ny >= 0 && ny < M){

			int swap;
			swap = finish[x][y];
			finish[x][y] = finish[nx][ny];
			finish[nx][ny] = swap;
			if(dfs(d + 1, nx, ny))
				return 1;
			else{

				swap = finish[x][y];
				finish[x][y] = finish[nx][ny];
				finish[nx][ny] = swap;
			}
		}
	}
	return 0;
}

int main(){

	scanf("%d%*c", &t);
	while(t--){

		int i, j, x, y;
		for(i = 0; i < M; i++){

			for(j = 0; j < M; j++){

				scanf("%c", &finish[i][j]);
				if(finish[i][j] == ' '){

					x = i;
					y = j;
				}

			}
			getchar();
		}
		for(deep = 0; deep < 11; deep++)
			if(dfs(0, x, y))
				break;

		if(deep != 11)
			printf("Solvable in %d move(s).\n", deep);
		else
			printf("Unsolvable in less than 11 move(s).\n");

	}
	return 0;
}


你可能感兴趣的:(10422 - Knights in FEN(迭代深度搜索))