Eight II HDU - 3567

Eight II HDU - 3567

知识点: bfs 打表, 康托展开

思路: 先预处理"X12345678",“1X2345678”,“12X345678”,“123X45678”,“1234X5678”,“12345X678”,
“123456X78”,“1234567X8”,"12345678X"等状态
每次将给定的s1映射为9个状态中的一个x1,将s2通过s1到x1的映射得到目标状态x2,再根据打表得到答案即可
使用康托展开为了压缩空间

#include <iostream>
#include <vector>
#include <cstdio>
#include <queue>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 9, MAXN = 4e5;

int f[N + 1];
int d[4][2] = {{1, 0}, {0, -1}, {0, 1}, {-1, 0}};
string ops = "dlru";  // 这里的顺序不能改变,因为答案要输出字典序最小的

int vis[N][MAXN];
int pre[N][MAXN];

struct Node {
	int status[N];   // 当前的状态
	int idx; // x的位置
	int hash;  // hash值
};

int cantor(int s[]) {
	int res = 0;
	for(int i = 0; i < N; i++) {
		int sum = 0;
		for(int j = i + 1; j < N; j++) 
			if(s[i] > s[j]) sum++;
		res += sum * f[N - i - 1];
	}
	return res;
}


void bfs(int k) {
	Node start, cur, temp;
	for(int i = 0, v = 1; i < N; i++)
		if(i == k) start.status[i] = 0;
		else start.status[i] = v++;
	
	start.idx = k;
	start.hash = cantor(start.status);

	
	queue<Node> q;
	q.push(start);
	
	vis[k][start.hash] = 1;
	
	while(q.size()) {
		cur = q.front();
		q.pop();
		
		int x = cur.idx / 3, y = cur.idx % 3;
		for(int i = 0; i < 4; i++) {
			int xx = x + d[i][0], yy = y + d[i][1];

			if(xx < 0 || xx >= 3 || yy < 0 || yy >= 3) continue;
			
			temp = cur;
			swap(temp.status[temp.idx], temp.status[xx * 3 + yy]);
			temp.hash = cantor(temp.status);
			
			if(vis[k][temp.hash] == -1) {
				temp.idx = xx * 3 + yy;
				vis[k][temp.hash] = i;
				pre[k][temp.hash] = cur.hash;
				q.push(temp);
			}
		}
		
	}
		
}

void init() {
	f[0] = f[1] = 1;
	for(int i = 2; i <= N; i++) f[i] = f[i - 1] * i;
	
	memset(vis, -1, sizeof vis);
	memset(pre, -1, sizeof pre);
	
	for(int i = 0; i < N; i++) 	bfs(i);
	
}

int main() {
	init();
	
	freopen("in.txt", "r", stdin);
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int T;
	cin >> T;
	
	string s1, s2;
	for(int i = 0; i < T; i++) {
		cin >> s1 >> s2;
		int x1[N], x2[N];
		for(int i = 0, v = 1; i < N; i++) {
			if(s1[i] == 'X') x1[i] = 0;
			else x1[i] = v++;
		}
		for(int i = 0; i < N; i++) {
			if(s2[i] == 'X') x2[i] = 0;
			else {
				for(int j = 0; j < N; j++) 
					if(s2[i] == s1[j])
						x2[i] = x1[j];
			}
		}
		int k = s1.find('X');
		int hash = cantor(x2);
		string res = "";
		while(hash != -1) {
			res += ops[vis[k][hash]];
			hash = pre[k][hash];
		}
		printf("Case %d: %d\n", i + 1, res.size() - 1);
		for(int i = res.size() - 2; i >= 0; i--) printf("%c", res[i]);
		printf("\n");
	}
	return 0;
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值