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