挑战程序设计竞赛2.1习题:Seven Puzzle Aizu - 0121

日文原文:

7 パズル

7 パズルは 8 つの正方形のカードとこれらのカードがぴたりと収まる枠で構成されています。それぞれのカードには、互いに区別できるように 0, 1, 2, ..., 7 と番号がつけられています。枠には、縦に 2 個、横に 4 個のカードを並べることができます。

7 パズルを始めるときには、まず枠にすべてのカードを入れます。枠のなかで 0 のカードだけは、上下左右に隣接するカードと位置を交換することができます。たとえば、枠の状態が図(a) のときに、0 のカードの右に隣接した、7 のカードと位置を交換すれば、図(b) の状態になります。あるいは、図(a) の状態から 0 のカードの下に隣接した 2 のカードと位置を交換すれば図(c) の状態になります。図(a) の状態で 0 のカードと上下左右に隣接するカードは 7 と 2 のカードだけなので、これ以外の位置の入れ替えは許されません。

ゲームの目的は、カードをきれいに整列して図(d) の状態にすることです。最初の状態を入力とし、カードをきれいに整列するまでに、必要な最小手数を出力するプログラムを作成してください。ただし、入力されたカードの状態からは図(d) の状態に移ることは可能であるとします。

入力データは、1 行に 8 つの数字が空白区切りで与えられます。これらは、最初の状態のカードの並びを表します。例えば、図(a) の数字表現は0 7 3 4 2 5 1 6 に、図(c) は 2 7 3 4 0 5 1 6 となります。

図(a) 0 7 3 4 2 5 1 6 の場合図(b) 7 0 3 4 2 5 1 6 の場合


図(c) 2 7 3 4 0 5 1 6 の場合図(d) 0 1 2 3 4 5 6 7 (最終状態)

 

Input

上記形式で複数のパズルが与えられます。入力の最後まで処理してください。 与えられるパズルの数は 1,000 以下です。

Output

各パズルについて、最終状態へ移行する最小手数を1行に出力してください。

Sample Input

0 1 2 3 4 5 6 7
1 0 2 3 4 5 6 7
7 6 5 4 3 2 1 0

Output for the Sample Input

0
1
28

7拼图

7拼图由八张方形卡片和一个适合这些卡片的框架组成。每张卡的编号分别为0、1、2,...,7,以使其彼此区分。您可以在框架中垂直排列两张卡片,水平排列四张卡片。

7当您开始拼图时,首先将所有卡片放入框中。只能将框架中的0卡与顶部,底部,左侧和右侧的相邻卡互换。例如,如果框的状态如图(A)所示,并且位置被替换为与第0张卡的右侧相邻的第7张卡,则状态将如图(B)所示。或者,如果从图(A)的状态交换位置并且在第0张卡下方相邻的2卡,则将获得图(C)的状态。在图(A)的状态下,与第0张卡以及第7和第2张卡相邻的唯一卡是顶部,底部,左侧和右侧的卡。

游戏的目的是如图(d)所示整齐地排列卡片。创建一个程序,将初始状态作为输入,并输出整齐排列卡片所需的最少步骤数。然而,假定可以从输入卡的状态移动到图(D)的状态。

输入数据每行有八个数字,以空格分隔。这些代表初始卡序列。例如,图(a)用0 7 3 4 2 5 16表示,图(c)用2 7 3 4 0 5 16表示。

图(a)0 7 3 4 2 5 1 6图(b)7 0 3 4 2 5 1 6


图(c)2 7 3 4 0 5 1 6图(c)2 7 3 4 0 5 1 6

 

 

 

输入项

以上格式给出了多个谜题。请处理到输入的结尾。给出的谜题数量少于1,000。

输出量

对于每个拼图,在一行上输出最小移动数到最终状态。

样本输入
0 1 2 3 4 5 6 7
1 0 2 3 4 5 6 7
7 6 5 4 3 2 1 0

样本输出
0
1
28

这道题,其实很简单,原以为数据量很大而询问很少,结果反了,正确做法应该是因为目标状态是已知的,倒着搜索所有的可能,然后记录每种可能的步数,然后询问就O(1)输出就OK了。

AC代码:

#include <stdio.h>
#include <queue>
#include <string.h>
#include <map>
using namespace std;
struct Node{
int zero_place;
int ans;//以整数的形式记录每个数字
}temp;
map<int, int> m;//每一个形式所对应的步数
int a[10];
queue<Node>q;
int ans;
bool vis[1000000000];
void cal()//数组转ans
{
	int t = 0;
	for(int i = 0; i < 8; i++)
	{
		t *= 10;
		t += a[i];
	}
	temp.ans = t;
}
void recal(Node temp)//ans转数组
{
	int t = temp.ans;
	for(int i = 0; i < 8; i++)
	{
		a[7 - i] = t % 10;
		t /= 10;
	}
}
void rebfs()
{
	q.push(temp);
	while(!q.empty())
	{
		Node now = q.front();
		q.pop();
		
		temp = now;
		recal(now);
		if(temp.zero_place % 4)
		{
			temp.zero_place -= 1;
			a[temp.zero_place + 1] = a[temp.zero_place];
			a[temp.zero_place] = 0;
			cal();
			if(!vis[temp.ans])
			{
				m[temp.ans] = m[now.ans] + 1;
				q.push(temp);
				vis[temp.ans] = true;
			}
		}
		
		
		temp = now;
		recal(now);
		if((temp.zero_place % 4) < 3)
		{
			temp.zero_place += 1;
			a[temp.zero_place - 1] = a[temp.zero_place];
			a[temp.zero_place] = 0;
			cal();
			if(!vis[temp.ans])
			{
				m[temp.ans] = m[now.ans] + 1;
				q.push(temp);
				vis[temp.ans] = true;
			}
		}
		
		
		temp = now;
		recal(now);
		if(temp.zero_place < 4)
		{
			temp.zero_place += 4;
			a[temp.zero_place - 4] = a[temp.zero_place];
			a[temp.zero_place] = 0;
			cal();
			if(!vis[temp.ans])
			{
				m[temp.ans] = m[now.ans] + 1;
				q.push(temp);
				vis[temp.ans] = true;
			}
		}
		
		
		temp = now;
		recal(now);
		if(temp.zero_place >= 4)
		{
			temp.zero_place -= 4;
			a[temp.zero_place + 4] = a[temp.zero_place];
			a[temp.zero_place] = 0;
			cal();
			if(!vis[temp.ans])
			{
				m[temp.ans] = m[now.ans] + 1;
				q.push(temp);
				vis[temp.ans] = true;
			}
		}
		
	}
}
int main(void)
{
	for(int i = 0; i < 8; i++)
		a[i] = i;
	temp.zero_place = 0;
	temp.ans = 1234567;
	m[temp.ans] = 0;
	vis[temp.ans] = true;
	rebfs();
	while(scanf("%d", &a[0]) == 1)
	{
		for(int i = 1; i < 8; i++)
		{
			scanf("%d", &a[i]);
		}
		cal();
		printf("%d\n", m[temp.ans]); 
	}
	return 0;
}

  

posted @ 2020-01-15 15:59  funforever  阅读(179)  评论(0编辑  收藏  举报