这题难度颇大啊,TLE一天了,测试数据组数太多了。双向广度优先搜索不能得到字典序最小的,一直WA。

思路:利用IDA*算法,当前状态到达目标状态的可能最小步数就是曼哈顿距离,用于搜索中的剪枝。下次搜索的限制不能直接加1,会超时,应该从当前状态到目标状态最小限制开始搜索。

AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
const int maxn = 4e5 + 5;
int vis[maxn];
int st[9], goal[9];

const int dx[] = {1,0,0,-1};
const int dy[] = {0,-1,1,0};
const char dir[] = {'d','l','r','u'};

int fact[9], loc[9];
void deal() {  //1~8阶乘打表,方便编码
	fact[0] = 1;
	for(int i = 1; i < 9; ++i) fact[i] = fact[i - 1] * i;
}

int KT(int *a) {
	int code = 0;
	for(int i = 0; i < 9; ++i) {
		int cnt = 0;
		for(int j = i + 1; j < 9; ++j) if(a[j] < a[i]) cnt++;
		code += fact[8 - i] * cnt;
	}
	return code;
}

void get_pos() {
	for(int i = 0; i < 9; ++i) {
		loc[goal[i]] = i;
	}
}

int get_h(int *a) { //曼哈顿距离
	int cnt = 0;
	for(int i = 0; i < 9; ++i) {
		if(a[i] == 0 || i == loc[a[i]]) continue;
		int x = i / 3, y = i % 3;
		int n = loc[a[i]];
		int px = n / 3, py = n % 3;
		cnt += abs(x - px) + abs(y - py);
	}
	return cnt;
}

char ans[50];
int a[9];

// step + h <= maxd
int maxd, nextd;
int dfs(int step, int pos) {
	int h = get_h(a); // cut
	//printf("h = %d\n", h);
	if(h == 0) {
		printf("%d\n", step);
		ans[step] = '\0';
		printf("%s", ans);
		return 1;
	}
	if(step + h > maxd) {
		nextd = min(nextd, step + h);
		return 0;
	}
	int x = pos / 3, y = pos % 3;
	for(int i = 0; i < 4; ++i) {
		int px = x + dx[i], py = y + dy[i];
		if(px < 0 || py < 0 || px >= 3 || py >= 3) continue;
		int pz = px * 3 + py;
		swap(a[pos], a[pz]);
		int code = KT(a);
		if(vis[code]) {
			swap(a[pos], a[pz]);
			continue;
		}
		vis[code] = 1;
		ans[step] = dir[i];
		if(dfs(step + 1, pz)) return 1;
		vis[code] = 0;
		swap(a[pos], a[pz]);
	}
	return 0;
}

int main() {
	deal();
	char str[50];
	int T, kase = 1;
	scanf("%d", &T);
	while(T--) {
		int pos;
		scanf("%s", str);
		for(int i = 0; i < 9; ++i) {
			if(str[i] == 'X') {
				pos = i;
				st[i] = 0;
			}
			else st[i] = str[i] - '0';
		}

		scanf("%s", str);
		for(int i = 0; i < 9; ++i) {
			if(str[i] == 'X') goal[i] = 0;
			else goal[i] = str[i] - '0';
		}
		get_pos();

		printf("Case %d: ", kase++);

		int code = KT(st);
		vis[code] = 1;
		for(maxd = get_h(st);;) {
			nextd = 1 << 30;
			memcpy(a, st, sizeof(a));
			memset(vis, 0, sizeof(vis));
			if(dfs(0, pos)) break;
			maxd = nextd;
		}
		printf("\n");
	}
	return 0;
}

如有不当之处欢迎指出!

04-17 21:11