六数码问题
描述:
现有一两行三列的表格如下:
A B C
D E F
把1、2、3、4、5、6六个数字分别填入A、B、C、D、E、F格子中,每个格子一个数字且各不相同。每种不同的填法称为一种布局。如下:
1 3 5
2 4 6
布局1
2 5 6
4 3 1
布局2
定义α变换如下:把A格中的数字放入B格,把B格中的数字放入E格,把E格中的数字放入D格,把D格中的数字放入A格。
定义β变换如下:把B格中的数字放入C格,把C格中的数字放入F格,把F格中的数字放入E格,把E格中的数字放入B格。
问:对于给定的布局,可否通过有限次的α变换和β变换变成下面的目标布局:
1 2 3
4 5 6
目标布局
输入:
本题有多个测例,每行一个,以EOF为输入结束标志。每个测例的输入是1到6这六个数字的一个排列,空格隔开,表示初始布局ABCDEF格中依次填入的数字。
输出:
每个输出占一行。可以转换的,打印Yes;不可以转换的,打印No。
输入样例:
1 3 5 2 4 6
2 5 6 4 3 1
输出样例:
No
Yes
源代码
#include <iostream>
#include <stdio.h>
#include <queue>
using namespace std;
int a[6];
int vis[7][7][7][7][7][7];
void swap(int &a,int &b)
{
int temp = a;
a = b;
b = temp;
}
void alpha(int *a)
{
swap(a[0], a[1]);
swap(a[0], a[4]);
swap(a[0], a[3]);
}
void beta(int *a)
{
swap(a[1], a[2]);
swap(a[1], a[5]);
swap(a[1], a[4]);
}
bool bfs()
{
queue<int> q;
vis[a[0]][a[1]][a[2]][a[3]][a[4]][a[5]] = 1;
int b[6];
q.push(a[0] * 100000 + a[1] * 10000 + a[2] * 1000 + a[3] * 100 + a[4] * 10 + a[5]);
while(!q.empty())
{
int pop_num = q.front();
q.pop();
b[5] = pop_num % 10;
b[4] = pop_num / 10 % 10;
b[3] = pop_num / 100 % 10;
b[2] = pop_num / 1000 % 10;
b[1] = pop_num / 10000 % 10;
b[0] = pop_num / 100000 % 10;
alpha(b);
if(vis[b[0]][b[1]][b[2]][b[3]][b[4]][b[5]] != 1)
{
if(vis[b[0]][b[1]][b[2]][b[3]][b[4]][b[5]] == -1)
{
return true;
}
q.push(b[0] * 100000 + b[1] * 10000 + b[2] * 1000 + b[3] * 100 + b[4] * 10 + b[5]);
vis[b[0]][b[1]][b[2]][b[3]][b[4]][b[5]] = 1;
}
alpha(b);
alpha(b);
alpha(b);
beta(b);
if(vis[b[0]][b[1]][b[2]][b[3]][b[4]][b[5]] != 1)
{
if(vis[b[0]][b[1]][b[2]][b[3]][b[4]][b[5]] == -1)
{
return true;
}
q.push(b[0] * 100000 + b[1] * 10000 + b[2] * 1000 + b[3] * 100 + b[4] * 10 + b[5]);
vis[b[0]][b[1]][b[2]][b[3]][b[4]][b[5]] = 1;
}
}
return false;
}
int main()
{
vis[1][2][3][4][5][6] = -1;
while (scanf("%d%d%d%d%d%d",&a[0],&a[1],&a[2],&a[3],&a[4],&a[5])!=EOF)
{
int flag = bfs();
if(flag == true)
cout << "Yes" << endl;
else
cout << "No" << endl;
}
}
思路
六数码问题数据量小,查重可以使用六维数组。
- α \alpha α变化,若无重复,则记录并入队
- 三次 α \alpha α变化恢复回去,再进行 β \beta β变化。
- 若无重复,则记录并入队。
- 检查是否到达目标顺位,到了则返回true。
- 队列为空还没有到达,返回false。