UVA - 704 Colour Hash(双向bfs+hash+线性表)


  Colour Hash 

This puzzle consists of two wheels. Both wheels can rotate both clock and counter-clockwise. They contain 21 coloured pieces, 10 of which are rounded triangles and 11 of which are separators. Figure 1 shows the final position of each one of the pieces. Note that to perform a one step rotation you must turn the wheel until you have advanced a triangle and a separator.


Figure 1. Final puzzle configuration

Your job is to write a program that reads the puzzle configuration and prints the minimum sequence of movements required to reach the final position. We will use the following integer values to encode each type of piece:


0grey separator
1yellow triangle
2yellow separator
3cyan triangle
4cyan separator
5violet triangle
6violet separator
7green triangle
8green separator
9red triangle
10red separator


A puzzle configuration will be described using 24 integers, the first 12 to describe the left wheel configuration and the last 12 for the right wheel. The first integer represents the bottom right separator of the left wheel and the next eleven integers describe the left wheel clockwise. The thirteenth integer represents the bottom left separator of right wheel and the next eleven integers describe the right wheel counter-clockwise.

The final position is therefore encoded like:

0 3 4 3 0 5 6 5 0 1 2 1 0 7 8 7 0 9 10 9 0 1 2 1

If for instance we rotate the left wheel clockwise one position from the final configuration (as shown in Figure 2) the puzzle configuration would be encoded like:

2 1 0 3 4 3 0 5 6 5 0 1 0 7 8 7 0 9 10 9 0 5 0 1


Figure 2. The puzzle after rotating the left wheel on step clockwise from the final configuration.

Input 

Input for your program consists of several puzzles. The first line of the input will contain an integer n specifying the number of puzzles. There will then be n lines each containing 24 integers separated with one white space, describing the initial puzzle configuration as explained above.

Output 

For each configuration your program should output one line with just one number representing the solution. Each movement is encoded using one digit from 1 to 4 in the following way:


1Left Wheel Clockwise rotation
2Right Wheel Clockwise rotation
3Left Wheel Counter-Clockwise rotation
4Right Wheel Counter-Clockwise rotation


No space should be printed between each digit. Since multiple solutions could be found, you should print the solution that is encoded as the smallest number. The solution will never require more than 16 movements.

If no solution is found you should print ``NO SOLUTION WAS FOUND IN 16 STEPS". If you are given the final position you should print ``PUZZLE ALREADY SOLVED".

Sample Input 

3
0 3 4 3 0 5 6 5 0 1 2 1 0 7 8 7 0 9 10 9 0 1 2 1
0 3 4 5 0 3 6 5 0 1 2 1 0 7 8 7 0 9 10 9 0 1 2 1
0 9 4 3 0 5 6 5 0 1 2 1 0 7 8 7 0 9 10 3 0 1 2 1

Sample Output 

PUZZLE ALREADY SOLVED
1434332334332323
NO SOLUTION WAS FOUND IN 16 STEPS


题目大意:一个拼图由两个转盘组成,两个转盘都可以沿着顺时针和逆时针方向旋转,这个拼图由11片组成,其中10片是三角形的,11片是骨头形的。

每种编号对应的拼图如下:
0 grey separator
1 yellow triangle
2 yellow separator
3 cyan triangle
4 cyan separator
5 violet triangle
6 violet separator
7 green triangle
8 green separator
9 red triangle
10 red separator

最终状态是(见图1):
0 3 4 3 0 5 6 5 0 1 2 1 0 7 8 7 0 9 10 9 0 1 2 1


将最终状态的拼图,左边转盘沿着逆时针旋转两格,状态是(见图2):
2 1 0 3 4 3 0 5 6 5 0 1 0 7 8 7 0 9 10 9 0 5 0 1

现在给你一个初始状态,问你能否在16步之内,转出结束状态,如果可以请打印出过程:

过程及对应的编号如下:

1 左边转盘顺时针旋转
2 右边转盘顺时针旋转
3 左边转盘逆时针旋转
4 右边转盘逆时针旋转

注意每次旋转只能旋转两格

解析:这题是道很复杂的bfs问题,单纯的bfs肯定会超时,所以要用到双向bfs,来求解该题。
双向bfs的思想:先逆向从结果状态搜索8层,然后再从正向搜索,一旦正向搜索“碰到”了逆向搜索搜出来的状态,那么即得出答案。如果正向搜到第8层还没有“碰到”逆向搜到的状态,那么就表示无解。由于目标状态只有一个,所以逆向搜索只要搜一次就可以了。

不懂的可以参考下图:

双向bfs(转载)

再看下状态是如何保存的,由图1和图2,可以推测出状态的编号如下
                    
    7  8        20 19 18
  6        9   21        17
5          10 22        16
4          11 23        15   
  3       0   12       14
    2  1         13 

注意:写旋转的时候头脑要保持十分清晰,不然非常容易出错。

对于如何判重,我的选择是将状态转换为一个字符串,存入map(或者set)中进行判断,不然如果转换为数字,需要将24位的状态,进行运算转换,最后求出的数字至少有24位,数字太大了,就算用long long 也存不下。


AC代码

#include <cstdio>
#include <cstring>
#include <queue>
#include <map>
#include <string>
using namespace std;
struct Node {
	int step[20];
	int dist;
	char st[25];
};
Node ans_front,ans_back;
map<string,bool> vis_back;
map<string,bool> vis_front;
map<string,Node> back_path;
const char goal[] = "034305650121078709:90121";
void rotate(char next[],char origin[],int dir) {
	char tmp1,tmp2;
	switch(dir) {
		case 1: //左边顺时针移动2格
			tmp1 = origin[10];
			tmp2 = origin[11];
			for(int i = 9; i >= 0; i--) {
				next[i+2] = next[i];
			}
			next[0] = tmp1;
			next[1] = tmp2;
			next[21] = next[9];
			next[22] = next[10];
			next[23] = next[11];
			break;
		case 2: //右边顺时针移动2格
			tmp1 = origin[12];
			tmp2 = origin[13];
			for(int i = 12; i <= 21; i++) {
				next[i] = next[i+2];
			}
			next[22] = tmp1;
			next[23] = tmp2;
			next[9] = next[21];
			next[10] = next[22];
			next[11] = next[23];
			break;
		case 3: //左边逆时针移动2格
			tmp1 = origin[0];
			tmp2 = origin[1];
			for(int i = 2; i <= 11; i++) {
				next[i-2] = next[i];
			}
			next[10] = tmp1;
			next[11] = tmp2;
			next[21] = next[9];
			next[22] = next[10];
			next[23] = next[11];
			break;
		case 4: //右边逆时针移动2格
			tmp1 = origin[22];
			tmp2 = origin[23];
			for(int i = 23; i >= 12; i--) {
				next[i] = next[i-2];
			}
			next[12] = tmp1;
			next[13] = tmp2;
			next[9] = next[21];
			next[10] = next[22];
			next[11] = next[23];		
			break;
	}
}
void back_bfs() {
	vis_back.clear();
	back_path.clear();
	Node end;
	end.dist = 0;
	strcpy(end.st,goal);
	queue<Node> q;
	q.push(end);
	vis_back[end.st] = true;
	while(!q.empty()) {
		Node front = q.front();
		q.pop();
		for(int i = 1; i <= 4; i++) {
			Node t = front;
			rotate(t.st,front.st,i);
			if(!vis_back[t.st]) {
				t.dist = front.dist + 1;
				t.step[t.dist] = i;	
				vis_back[t.st] = true;
				back_path.insert(make_pair(t.st,t));		
				q.push(t);
			}
		}
		if(front.dist > 8) {
			return ;
		}
	}
}
bool front_bfs(char str[]) { //正向bfs
	vis_front.clear();
	Node start;
	start.dist = 0;
	strcpy(start.st,str); //将最终状态复制给end
	queue<Node> q;
	q.push(start);
	vis_front[start.st] = true;
	while(!q.empty()) {
		Node front = q.front();
		q.pop();
		if(vis_back[front.st]) {
			ans_back = back_path[front.st];
			ans_front = front;
			return true;
		}
		for(int i = 1; i <= 4; i++) {
			Node t = front;
			rotate(t.st,front.st,i);
			if(!vis_front[t.st]) {
				t.dist = front.dist + 1;
				t.step[t.dist] = i;
				vis_front[t.st] = true;
				q.push(t);
			}
		}
		if(front.dist > 8) {
			return false;
		}
	}
	return false;
}
int main() {
	back_bfs();
	char start[24];
	int piece;
	int t;
	scanf("%d",&t);
	while(t--) {
		for(int i = 0; i < 24; i++) {
			scanf("%d",&piece);
			start[i] = piece + '0';
		}
		start[24] = '\0';
		if(!memcmp(start,goal,sizeof(goal))) {
			printf("PUZZLE ALREADY SOLVED\n");
			continue;
		}
		int res = front_bfs(start);
		if(res) {
			for(int i = 1; i <= ans_front.dist; i++) {
				printf("%d",ans_front.step[i]);
			}
			for(int i = ans_back.dist; i >= 1; i--) {
				switch(ans_back.step[i]) {
					case 1:
						printf("3");
						break;
					case 2:
						printf("4");
						break;
					case 3:
						printf("1");
						break;
					case 4:
						printf("2");
						break;
				}
			}
			printf("\n");
		}else {
			printf("NO SOLUTION WAS FOUND IN 16 STEPS\n");
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值