挑战程序设计竞赛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;
}

浙公网安备 33010602011771号