描述
有n个棋子(n≥4)排成一行,开始位置为白子全部在左边,黑子全部在右边,如下图为n=5的情形:○○○○○●●●●●
移动棋子的规则是:每次必须同时移动相邻的两个棋子,颜色不限,可以左移也可以右移到空位上去,但不能调换两个棋子的左右位置。每次移动必须跳过若干个棋子(不能平移),要求最后能移成黑白相间的一行棋子。如n=5时,成为:○●○●○●○●○●
任务:编程打印出移动过程。
格式
输入格式
输入n。
输出格式
移动过程。
样例
输入样例
7
输出样例
step 0:ooooooo*******--
step 1:oooooo--******o*
step 2:oooooo******--o*
step 3:ooooo--*****o*o*
step 4:ooooo*****--o*o*
step 5:oooo--****o*o*o*
step 6:oooo****--o*o*o*
step 7:ooo--***o*o*o*o*
step 8:ooo*o**--*o*o*o*
step 9:o--*o**oo*o*o*o*
step10:o*o*o*--o*o*o*o*
step11:--o*o*o*o*o*o*o*
限制
时间限制: 1000 ms
内存限制: 65536 KB
思想:和很多解法一样的分治递归。
分析:先看样例找移动的规律,当黑白棋子都大于4时,总是将中间的一对两个不同的棋子移到最右边的空位,然后再将最左边的黑棋子移到中间,如此反复,直到当黑白棋子各为4时,后面的移动方式开始与前面的不同:
- 先将第4、5个棋子移到右边空位。
- 将第8、9位置的棋子移到先前的空位。
- 将2、3位置的棋子移到先前的空位。
- 将7、8位置的棋子移到先前的空位。
- 将1、2位置的棋子移到之前的空位。
规律找到,也就找到了函数的处理过程。
每一个递归算法都需要出口,出口就是快结束的点,可以根据上面的规律分析n=4时是出口。
递归操作都是用来处理下一次的过程,所以需要参数,根据分治递归思想和以上的分析,当n=7时,问题可以分解成n=6的情况,n=6时,问题可以分解成n=5的情况,直到递归的出口n=4,所以参数为n-1,。
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
char a[105];
int n, num=0, cur;
void print();
void recursive(int);
void move(int);
int main()
{
scanf ("%d", &n);
for (int i=1; i<=n; i++) {
a[i] = 'o';
}
for (int i=n+1; i<=2*n; i++) {
a[i] = '*';
}
cur = 2*n+1;
a[cur] = '-';
a[cur+1] = '-';
print();
recursive(n);
return 0;
}
void recursive(int n) {
if (n == 4) {
move(4);
move(8);
move(2);
move(7);
move(1);
} else {
move(n);
move(2*n-1);
recursive(n-1);
}
}
void move(int n) {
for (int i=0; i<2; i++) {
a[cur+i] = a[n+i];
a[n+i] = '-';
}
cur = n;
print();
}
void print() {
printf ("step%2d:", num++);
for (int i=1; i<=2*n+2; i++) {
printf ("%c", a[i]);
}
printf ("\n");
}