1. 程式人生 > >搜尋_IDA*_A*_BZOJ1085_騎士精神

搜尋_IDA*_A*_BZOJ1085_騎士精神

點此開啟題目頁面

Description

  在一個5×5的棋盤上有12個白色的騎士和12個黑色的騎士, 且有一個空位。在任何時候一個騎士都能按照騎
士的走法(它可以走到和它橫座標相差為1,縱座標相差為2或者橫座標相差為2,縱座標相差為1的格子)移動到空
位上。 給定一個初始的棋盤,怎樣才能經過移動變成如下目標棋盤: 為了體現出騎士精神,他們必須以最少的步
數完成任務。

Input

  第一行有一個正整數T(T<=10),表示一共有N組資料。接下來有T個5×5的矩陣,0表示白色騎士,1表示黑色騎
士,*表示空位。兩組資料之間沒有空行。

Output

  對於每組資料都輸出一行。如果能在15步以內(包括15步)到達目標狀態,則輸出步數,否則輸出-1。

Sample Input

2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
 

Sample Output

7
-1

思路分析:

    使用IDA*或A*均可, 估價函式為當前格局與目標格局除空格之外對應位置上元素不相同的元素的個數(為達到目標狀態, 這些上的騎士必須跳到空格處), 下面給出基於此策略的AC程式碼, 第一個為基於IDA*的解法, 第二個為基於A*的解法

//BZOJ1085_騎士精神
#include <iostream>
#include <cstdio> 
using namespace std;
const int dx[8] = {-1, -2, -2, -1, 1, 2, 2, 1};
const int dy[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
const char tar[6][6] = {{'0', '0', '0', '0', '0', '0'}
                      , {'0', '1', '1', '1', '1', '1'}
                      , {'0', '0', '1', '1', '1', '1'}
                      , {'0', '0', '0', '*', '1', '1'}
                      , {'0', '0', '0', '0', '0', '1'}
                      , {'0', '0', '0', '0', '0', '0'}};
char G[6][7];
int maxDeep;
////返回當前局面與目標局面同一位置不同元素的個數 
int F(){
    int res = 0;
    for(int i = 1; i <= 5; ++i)
        for(int j = 1; j <= 5; ++j) 
            if(tar[i][j] != G[i][j] && tar[i][j] != '*') ++res;
    return res;
}
//已經進行now次變換, 空格在第sx行, sy列處 
bool dfs(int now, int sx, int sy){
    int f = F(); if(now + f > maxDeep) return false;
    if(now == maxDeep) return true; 
    for(int i = 0; i <= 7; ++i){
        int x = sx + dx[i], y = sy + dy[i];
        if(x >= 1 && x <= 5 && y >= 1 && y <= 5){
            swap(G[sx][sy], G[x][y]);
            if(dfs(now + 1, x, y)) return true;
            swap(G[sx][sy], G[x][y]);
        } 
    }
    return false;   
}
int main(){
    int T; scanf("%d", &T);
    while(T--){
        for(int i = 1; i <= 5; ++i) scanf("%s", G[i] + 1);
        int sx, sy;
        for(int i = 1; i <= 5; ++i)
            for(int j = 1; j <= 5; ++j)
                if(G[i][j] == '*'){
                    sx = i, sy = j;
                    goto GO1;
                }
        GO1:
        if(!F()){
            cout << 0 << endl; continue;
        }
        maxDeep = 0; while(++maxDeep, maxDeep <= 15 && !dfs(0, sx, sy));
        if(maxDeep <= 15) cout << maxDeep << endl; else cout << -1 << endl;
    }
    return 0;
}
//BZOJ1085_騎士精神_A_Star
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <string>
#include <cstring>
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef pair<int, int> pii;
typedef pair<pii, string> piis;
const int INF = 0x3f3f3f3f;
const int dx[8] = {-1, -2, -2, -1, 1, 2, 2, 1};
const int dy[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
const char tar[6][6] = {{'0', '0', '0', '0', '0', '0'}
					  , {'0', '1', '1', '1', '1', '1'}
					  , {'0', '0', '1', '1', '1', '1'}
					  , {'0', '0', '0', '*', '1', '1'}
					  , {'0', '0', '0', '0', '0', '1'}
					  , {'0', '0', '0', '0', '0', '0'}};
char G[6][6]; 
//根據字串str還原陣列arr
void toArr(const string &str, char arr[6][6]){
	for(int i = 1, k = 0; i <= 5; ++i)
		for(int j = 1; j <= 5; ++j) arr[i][j] = str[k++];
} 
//返回arr對應的字串
void toStr(const char arr[6][6], string &str){
	char s[26]; s[25] = '\0';
	for(int i = 1, k = 0; i <= 5; ++i)
		for(int j = 1; j <= 5; ++j) s[k++] = arr[i][j];
	str = s;
} 
//返回arr的估價函式值
int F(const char arr[6][6]){
	int res = 0;
	for(int i = 1; i <= 5; ++i)
		for(int j = 1; j <= 5; ++j) 
			if(arr[i][j] != '*' && arr[i][j] != tar[i][j]) ++ res;
	return res;
} 
//返回arr中, 空格所在位置
void getSpace(const char arr[6][6], int &x, int &y){
	for(int i = 1; i <= 5; ++i)
		for(int j = 1; j <= 5; ++j)
			if(arr[i][j] == '*'){
				x = i, y = j; return;
			}
} 
int main(){
	int T; scanf("%d", &T);
	while(T--){
		char s[7];
		for(int i = 1; i <= 5; ++i)
			scanf("%s", s + 1), memcpy(G[i] + 1, s + 1, sizeof(char) * 5);
		//first.first:實際代價+估價函式值, first.second:實際代價, second:對應字串 
		priority_queue<piis , vector<piis>, greater<piis> > pq;
		string beg; toStr(G, beg);
		string end; toStr(tar, end);
		int res = -1;
		pq.push(mp(mp(F(G), 0), beg));
		while(pq.size() && pq.top().fi.fi <= 15){
			int v = pq.top().fi.se; string str = pq.top().se; pq.pop();
			if(str == end){
				res = v; break;
			}
			char arr[6][6]; toArr(str, arr); 
			int x, y; getSpace(arr, x, y);
			for(int i = 0; i <= 7; ++i){
				int a = x + dx[i], b = y + dy[i];
				if(a >= 1 && a <= 5 && b >= 1 && b <= 5){
					swap(arr[x][y], arr[a][b]);
					string ts; toStr(arr, ts);
					int f = F(arr), p = v + 1 + f; 
					if(p <= 15 || p == 15 && ts == end)
						pq.push(mp(mp(p, v + 1), ts));
					swap(arr[x][y], arr[a][b]);		
				}
			}
		}
		cout << res << endl;
	}	
	return 0;
}