PKU 1077 Eight

問題

8-パズルの初期盤面が与えられる。
これが解けるならその手順を、そうでないならunsolvableを出力せよ。

方針

幅優先探索
メモ化にmapを使うと間に合わないのでhashとかを使う。

ソースコード

適当に書いた自作hashmap

const int dy[] = {-1, 0, 1, 0}, dx[] = {0, -1, 0, 1};
const char *dirs = "uldr";
char ans[10000];
int len;

template<class K, class V>struct Map{
	ll *hs;
	V *data;
	const static int SZ = 999983;
	Map(){
		hs = new ll[SZ]; data = new V[SZ];
		rep(i, SZ) hs[i] = ~0;
	}
	~Map(){ delete(hs); delete(data); }
	
	ll hash(const K &key) const{
		return key;
	}
	void set(const K &key, const V &value){
		ll h = hash(key), i = h % SZ;
		for(; hs[i] != h && hs[i] != ~0; i = i == SZ - 1 ? 0 : i + 1);
		hs[i] = h;
		data[i] = value;
	}
	const V& get(const K &key) const{
		ll h = hash(key), i = h % SZ;
		for(; hs[i] != h && hs[i] != ~0; i = i == SZ - 1 ? 0 : i + 1);
		if(hs[i] != h) throw 0; //no such key
		return data[i];
	}
	bool contain(const K &key)const{
		ll h = hash(key), i = h % SZ;
		for(; hs[i] != h && hs[i] != ~0; i = i == SZ - 1 ? 0 : i + 1);
		return hs[i] == h;
	}
};

int main()
{
	vi v;
	char c;
	int y, x;
	ll start = 0;
	rep(i, 9){
		cin >> c;
		v.pb(c == 'x' ? 0 : c - '0');
		if(v.back() == 0) y = i / 3, x = i % 3;
		start *= 9; start += v.back();
	}
	Map<ll, int> prev;
	queue<ll> q;
	q.push(start);
	prev.set(start, -1);
	
	while(!q.empty()){
		ll s = q.front(); q.pop();
		bool finish = 1;
		rep(i, 9) v[8 - i] = s % 9, s /= 9;
		
		rep(i, 9){
			if(v[i] != (i + 1) % 9) finish = 0;
			if(v[i] == 0) y = i / 3, x = i % 3;
		}
		if(finish){
			while(1){
				ll s = 0;
				rep(i, 9) s *= 9, s += v[i];
				if(s == start) break;
				
				int d = prev.get(s), ny = y - dy[d], nx = x - dx[d];
				ans[len++] = dirs[d];
				
				swap(v[ny * 3 + nx], v[y * 3 + x]);
				swap(ny, y); swap(nx, x);
			}
			reverse(ans, ans + len);
			cout << ans << endl;
			goto END;
		}
		
		rep(d, 4){
			int ny = y + dy[d], nx = x + dx[d];
			if(ny < 0 || nx < 0 || ny >= 3 || nx >= 3) continue;
			swap(v[ny * 3 + nx], v[y * 3 + x]);
			
			ll nh = 0;
			rep(i, 9) nh *= 9, nh += v[i];
			if(!prev.contain(nh)){
				prev.set(nh, d);
				q.push(nh);
			}
			swap(v[ny * 3 + nx], v[y * 3 + x]);
		}
	}
	cout << "unsolvable" << endl;
	END:;
	return 0;
}