题目:有这样一个包含9个圆圈的数阵,如下图所示:
外层8个圈,内层一个圈;将1~8这8个数随机的填写到该数阵的外层的圆圈中,只剩下中间的一个空圆圈。规定每个数字只能按照数阵中的直线从一个圆圈移动到另一个空的圆圈中。通过若干步骤移动,要求将数阵中的数字移动成下图所示状态:
【样例】
输入:[1]—[2]—[4]
| \ | / |
[8]—[ ]—[3]
| / | \ |
[7]--[5]--[6]
输出:
3#——》0#
4#——》3#
0#——》4#
5#——》0#
6#——》5#
0#——》6#
[1]—[2]—[3]
| \ | / |
[8]-- [ ]--[4]
| / | \ |
[7]--[6]--[5]
方法:
将外圈中的数据看成一个链,头为图中1位置,尾为图中8位置,该链最初是8个无序的数据,最终排成如图所示状态,所以实际上就是一个数列的排序过程。但需要注意的是,这里只能用冒泡排序,因为按照题意,很容易测试出只需3步就可以交换相邻位置的两个数比如图中3,4。第一步,3->空,第二步,4->空,第三步,3->空。
这里最关键是,将图看成了一个链。最终要求就是一个排序后的链。所以问题转化为排序。但是这里的排序实际上人为的苛刻了。苛刻的条件是,在链上,只能同时交换相邻两个元素。但是我们知道,冒泡排序告诉我们,即时这样苛刻,排序也是必然可以完成的,因为冒泡排序就是这样的。之所以说苛刻了。是因为原本按照题意,我们可以交换首尾(图中1和8位置),但现在我们不允许这样做。按照题意,我们也可以随便移动(不仅仅是相邻),但这里我们也禁止了。
当然,没有任何迹象表明我们这样是最少步骤。虽然题意没有这点要求。
所以最最核心是问题的转化,将移动问题转化为苛刻条件下的冒泡排序。
完整的实现代码如下:
#include "iostream"
using namespace std;
int m[8];
void print()
{
cout<<"["<<m[0]<<"]-["<<m[1]<<"]-["<<m[2]<<"]"<<endl;
cout<<"["<<m[7]<<"]-[ ]-["<<m[3]<<"]"<<endl;
cout<<"["<<m[6]<<"]-["<<m[5]<<"]-["<<m[4]<<"]"<<endl;
}
void f()
{
int i,j;
for(i=0;i<7;i++)
{
for(j=7;j>=1;j--) //倒序遍历输入的8个元素
{
if(m[j]<m[j-1]) //相邻两个元素不满足条件时,交换
{
int temp=m[j];
m[j]=m[j-1];
m[j-1]=temp;
cout<<"-------------中间步骤-------------"<<endl;
print();
cout<<"----------------------------------"<<endl<<endl;
}
}
}
}
int main(void)
{
for(int i=0;i<8;i++)
{
cin>>m[i];
}
print();
cout<<endl;
f();
print();
cout<<endl;
system("pause");
return 0;
}
运行效果图如下: