UVa10085 - The most distant state

題目:計算一個八數碼狀態對應的最遠狀態,即需要移動最多步數的狀態。

分析:圖論,搜索。根據0的位置不同分為9類情況,打表計算每個類別的情況即可。

            如果0初始的位置相同則狀態為同一類別,只是位置編號不同;

            利用bfs計算9種狀態(0的位置不同)對應的最遠距離,存儲結果;

            (這裡就是普通的八數碼算法,bfs+康拓展開)

            對於每組輸入判斷輸入那個類別,然後對位置做映射即可。

說明:移動的任意一組解都可以,還有一道╮(╯▽╰)╭。

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>

using namespace std;

int  output_block[9][9];
char output_step[9][100];
int  puzzle[9][9] = {
	0, 1, 2, 3, 4, 5, 6, 7, 8,
	1, 0, 2, 3, 4, 5, 6, 7, 8,
	1, 2, 0, 3, 4, 5, 6, 7, 8,
	1, 2, 3, 0, 4, 5, 6, 7, 8,
	1, 2, 3, 4, 0, 5, 6, 7, 8,
	1, 2, 3, 4, 5, 0, 6, 7, 8,
	1, 2, 3, 4, 5, 6, 0, 7, 8,
	1, 2, 3, 4, 5, 6, 7, 0, 8,
	1, 2, 3, 4, 5, 6, 7, 8, 0,
};

// cantor_expansion_define
int factorial[9] = {0, 1, 2, 6, 24, 120, 720, 5040, 40320};
int cantor(int block[9])
{
	int value = 0;
	for (int i = 0; i < 9; ++ i) {
		int count = 0;
		for (int j = 0; j < i; ++ j) {
			if (block[j] > block[i]) {
				count ++;
			}
		}
		value = value + count*factorial[i];
	}
	return value;
}
// cantor_expansion_define_over

// judge_function_define
int can_left(int value) 
{
	if (value%3 != 0) {
		return value-1;
	}else {
		return -1;
	}
}

int can_right(int value) 
{
	if (value%3 != 2) {
		return value+1;
	}else {
		return -1;
	}
}

int can_up(int value) 
{
	if (value/3 != 0) {
		return value-3;
	}else {
		return -1;
	}
}

int can_down(int value) 
{
	if (value/3 != 2) {
		return value+3;
	}else {
		return -1;
	}
}

int (*function[])(int value) = {can_up, can_left, can_down, can_right};
// judge_function_define_over

int state(int block[9])
{
	int value = 0;
	for (int i = 0; i < 9; ++ i) {
		value = value*9 + block[i];
	}
	return value;
}

int unstate(int value, int block[9])
{
	int zero_position = 0;
	for (int i = 8; i >= 0; -- i) {
		block[i] = value%9;
		value /= 9;
		if (block[i] == 0) {
			zero_position = i;
		}
	}
	return zero_position;
}

char action[4] = {'U', 'L', 'D', 'R'};
char steps[3628800];
int  front[3628800];
int  visit[3628800];
int  queue[3628800];
int  bfs(int input[9], int out_value[9], char out_step[])
{
	int block[9];
	for (int i = 0; i < 9; ++ i) {
		block[i] = input[i];
	}
	memset(visit, 0, sizeof(visit));
	int cantor_value = cantor(block);
	int state_value = state(block);
	visit[cantor_value] = 1;
	int move = 0, save = 0;
	steps[save] = '#';
	queue[save ++] = state_value;
	while (move < save) {
		int now = queue[move ++];
		int now_zero = unstate(now, block);
		for (int i = 0; i < 4; ++ i) {
			int new_zero = function[i](now_zero);
			if (new_zero != -1) {
				swap(block[now_zero], block[new_zero]);
				cantor_value = cantor(block);
				state_value = state(block);
				if (!visit[cantor_value]) {
					visit[cantor_value] = 1;
					steps[save] = action[i];
					front[save] = move-1;
					queue[save ++] = state_value;
				}
				swap(block[now_zero], block[new_zero]);
			}
		}
	}
	unstate(queue[move-1], block);
	for (int i = 0; i < 3; ++ i) {
		for (int j = 0; j < 3; ++ j) {
			out_value[3*i+j] = block[3*i+j];
		}
	}
	int step_count = 0, now_place = move-1;
	while (steps[now_place] != '#') {
		out_step[step_count ++] = steps[now_place];
		now_place = front[now_place];
	}
	int left = 0, right = step_count-1;
	while (left < right) {
		swap(out_step[left], out_step[right]);
		left ++;
		right --;
	}
}

int main()
{
	// make list for 9 states
	for (int i = 0; i < 9; ++ i) {
		bfs(puzzle[i], output_block[i], output_step[i]);
	}
	
	int n;
	int input[9];
	int output[9];
	while (~scanf("%d",&n)) {
		for (int t = 1; t <= n; ++ t) {
			int index = 0;
			for (int i = 0; i < 9; ++ i) {
				scanf("%d",&input[i]);
				if (input[i] == 0) {
					index = i;
				}
			}
			
			for (int i = 0; i < 9; ++ i) {
				for (int j = 0; j < 9; ++ j) {
					if (puzzle[index][j] == output_block[index][i]) {
						output[i] = input[j];
						break;
					}
				}
			}
			printf("Puzzle #%d\n",t);
			for (int i = 0; i < 3; ++ i) {
				for (int j = 0; j < 3; ++ j) {
					printf("%d",output[3*i+j]);
					if (j != 2) {
						printf(" ");
					}else {
						printf("\n");
					}
				}
			}
			printf("%s\n\n",output_step[index]);
		}
	}
	
	return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值