uva 704(隐式图搜索)

题意:给出24个数字,按题目给出的旋转规律,是否能变成题目给出的目标序列,打印旋转的步骤。

题解:普通的bfs会超时,借鉴了别人的,当做练手写了个双向的bfs + 哈希,因为只有一个目标状态,所以循环之前从目标状态开始逆向搜8层,然后开始从输入序列开始正向搜索,要么正向搜不到八层就达到目标状态,或者中途和之前逆向已经搜到的某个状态重合时就是可以在16步内,注意输出逆向的时候步骤也需要改变,1对3、2对4。

#include <stdio.h>
#include <string.h>
const int MAXSIZE = 100000;

typedef int State[24];
const State tar = {0, 3, 4, 3, 0, 5, 6, 5, 0, 1, 2, 1, 0, 7, 8, 7, 0, 9, 10, 9, 0, 1, 2, 1};
struct ST  {
	State sta;
	int order[10];
}que[2][MAXSIZE];
State st;
int head[2][MAXSIZE], next[2][MAXSIZE], dist[2][MAXSIZE];
int flag, pre, over;

void rotation(int dire, int s, int k) {
	ST& temp = que[s][k];
	if (dire == 1) {
		int a = temp.sta[10];
		int b = temp.sta[11];
		for (int i = 11; i >= 2; i--)
			temp.sta[i] = temp.sta[i - 2];
		temp.sta[0] = a;
		temp.sta[1] = b;
		temp.sta[21] = temp.sta[9];
		temp.sta[22] = temp.sta[10];
		temp.sta[23] = temp.sta[11];
	}
	else if (dire == 2) {
		int a = temp.sta[12];
		int b = temp.sta[13];
		for (int i = 12; i < 22; i++)
			temp.sta[i] = temp.sta[i + 2];
		temp.sta[22] = a;
		temp.sta[23] = b;
		temp.sta[9] = temp.sta[21];
		temp.sta[10] = temp.sta[22];
		temp.sta[11] = temp.sta[23];
	}
	else if (dire == 3) {
		int a = temp.sta[0];
		int b = temp.sta[1];
		for (int i = 0; i < 10; i++)
			temp.sta[i] = temp.sta[i + 2];
		temp.sta[10] = a;
		temp.sta[11] = b;
		temp.sta[21] = temp.sta[9];
		temp.sta[22] = temp.sta[10];
		temp.sta[23] = temp.sta[11];
	}
	else {
		int a = temp.sta[22];
		int b = temp.sta[23];
		for (int i = 23; i >= 12; i--)
			temp.sta[i] = temp.sta[i - 2];
		temp.sta[12] = a;
		temp.sta[13] = b;
		temp.sta[9] = temp.sta[21];
		temp.sta[10] = temp.sta[22];
		temp.sta[11] = temp.sta[23];
	}
}

int hash(ST temp) {
	int v = 0;
	for (int i = 0; i < 24; i++)
		v = v * 5 + temp.sta[i];
	return v % MAXSIZE;
}

int try_insert(int cur, int k, int s) {
	int h = hash(que[k][cur]);
	int u = head[s][h];
	while (u) {
		if (memcmp(que[s][u].sta, que[k][cur].sta, sizeof(que[k][cur].sta)) == 0) {
			if (k + s == 1) {
				flag = 1;
				pre = u;
				return 1;
			}
			else
				return 0;
		}
		u = next[s][u];
	}
	if (s == k) {
		next[s][cur] = head[s][h];
		head[s][h] = cur;
		return 1;
	}
	return 0;
}

void bfs(int s) {
	int front = 1, rear = 2;
	memset(head[s], 0, sizeof(head[s]));
	memcpy(que[s][front].sta, st, sizeof(st));
	dist[s][front] = 0;
	try_insert(front, s, s);
	while (front < rear) {
		ST& st1 = que[s][front];
		if (dist[s][front] > 8)
			return;
		if (try_insert(front, s, 1 - s)) {
			over = front;
			return;
		}
		for (int i = 1; i <= 4; i++) {
			ST& temp = que[s][rear];
			temp = st1;
			dist[s][rear] = dist[s][front] + 1;
			rotation(i, s, rear);
			temp.order[dist[s][front]] = i;
			if (try_insert(rear, s, 1 - s)) {
				over = rear;
				return;
			}
			if (try_insert(rear, s, s))
				rear++;
		}
		front++;
	}
}

int main() {
	memcpy(st, tar, sizeof(tar));
	bfs(0);
	const int cor[5] = {0, 3, 4, 1, 2};
	int t;
	scanf("%d", &t);
	while (t--) {
		flag = pre = over = 0;
		for (int i = 0; i < 24; i++)
			scanf("%d", &st[i]);
		bfs(1);
		if (flag && dist[0][pre] + dist[1][over] <= 16 ) {
			if (dist[0][pre] + dist[1][over]) {
				for (int i = 0; i < dist[1][over] ; i++)
					printf("%d", que[1][over].order[i]);
				for (int i = dist[0][pre] - 1; i >= 0; i--)
					printf("%d", cor[que[0][pre].order[i]]);
				printf("\n");
			}
			else
				printf("PUZZLE ALREADY SOLVED\n");
		}
		else
			printf("NO SOLUTION WAS FOUND IN 16 STEPS\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值