搜索_A*_POJ1077_POJ1077_Eight

版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/84378680

点此打开题目页面

思路分析:

    考虑将8数码的每个格局对应一个9位的9进制数(long long类型), 如果直接使用BFS或DFS的一个直接结果是超时. 因此使用A*, 估价函数为从当前状态(格局)s和目标状态t相等元素的曼哈顿距离之和, 易证该估价函数满足要求. 下面给出基于此策略的AC代码:

//POJ1077_Eight
#include <iostream>
#include <functional>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#define mp make_pair
#define fi first
#define se second
using namespace std;
struct state; typedef long long ll; typedef pair<int, int> pii; typedef pair<pii, ll> piill; 
const int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};
const char dir[4] = {'u', 'd', 'l', 'r'};
map<int ,pii> vis;//vis[i].first:状态i对应的最少变换次数, second: 最后一次变换的操作 
priority_queue<piill, vector<piill>, greater<piill> > pq;  
struct state{
	int sta[4][4]; pii pos[10];//pos[i]:数字i在sta中位置 
	bool operator == (const state &a){
		for(int i = 1; i <= 3; ++i)
			for(int j = 1; j <= 3; ++j) if(sta[i][j] != a.sta[i][j]) return false;
		return true;
	}
	//返回本状态对象对应的9进制数
	ll getNum(){
		ll res = 0; 
		for(int i = 1; i <= 3; ++i)
			for(int j = 1; j <= 3; ++j) res = res * 9 + sta[i][j];
		return res;
	}  
	//从num还原本对象 
	void re(ll num){
		for(int i = 3; i >= 1; --i)
			for(int j = 3; j >= 1; --j) 
				sta[i][j] = num % 9, pos[num % 9].fi = i, pos[num % 9].se = j, num /= 9;
	}
	//返回当前状态到目标状态T的交换次数下限 
	int getCnt(const state &T){
		int res = 0; 
		for(int i = 0; i <= 8; ++i) 
			res += abs(pos[i].fi - T.pos[i].fi) + abs(pos[i].se - T.pos[i].se);	
		return res;
	}
	//交换state[a][b]和state[c][d]
	void Swap(int a, int b, int c, int d){
		swap(pos[sta[a][b]], pos[sta[c][d]]), swap(sta[a][b], sta[c][d]);	
	} 
};
state beg, tar;//初始状态, 目标状态 
int main(){
	//初始化tar 
	for(int i = 1, k = 0; i <= 3; ++i)
		for(int j = 1; j <= 3; ++j) tar.sta[i][j] = ++k, tar.pos[k].fi = i, tar.pos[k].se = j;
	tar.sta[3][3] = 0, tar.pos[0].fi = 3, tar.pos[0].se = 3;
	//初始化beg
	for(int i = 1, t; i <= 3; ++i)
		for(int j = 1; j <= 3; ++j){
			char ch; cin >> ch;
			if(ch == 'x') beg.sta[i][j] = 0, beg.pos[0].fi = i, beg.pos[0].se = j;
			else t = ch - '0', beg.sta[i][j] = t, beg.pos[t].fi = i, beg.pos[t].se = j;
		} 		
	ll bn = beg.getNum(), tn = tar.getNum();	
	pq.push(mp(mp(beg.getCnt(tar), 0), bn)), vis[bn] = mp(0, -1);
	while(!pq.empty()){
		int val = pq.top().fi.se; ll tnum = pq.top().se; pq.pop(); state s; s.re(tnum);
		if(tnum == tn) break;
		int x = s.pos[0].fi, y = s.pos[0].se;
		for(int i = 0, u, v; i <= 3; ++i)
			if(u = x + dx[i], v = y + dy[i], u >= 1 && u <= 3 && v >= 1 && v <= 3){
				state stmp = s; stmp.Swap(x, y, u, v); int z = stmp.getNum();
				if(vis.count(z)) continue;
				pq.push(mp(mp(val + 1 + stmp.getCnt(tar), val + 1), z))
				, vis[z] = mp(val + 1, i);		
			}
	}
	if(!vis.count(tn)) cout << "unsolvable" << endl;
	else{
		//还原出解决方案 
		vector<int> vec; ll k = tn;
		while(k != bn){
			int y = vis[k].se;
			vec.push_back(y); state s; s.re(k);
			s.Swap(s.pos[0].fi, s.pos[0].se, s.pos[0].fi - dx[y], s.pos[0].se - dy[y]);
			k = s.getNum();
		}
		for(int i = vec.size() - 1; i >= 0; --i) cout << dir[vec[i]]; cout << endl;
	}	
}

猜你喜欢

转载自blog.csdn.net/solider98/article/details/84378680