黑白棋子的移动(分治递归)

描述

有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时,后面的移动方式开始与前面的不同:

  1. 先将第4、5个棋子移到右边空位。
  2. 将第8、9位置的棋子移到先前的空位。
  3. 将2、3位置的棋子移到先前的空位。
  4. 将7、8位置的棋子移到先前的空位。
  5. 将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");
}
发布了89 篇原创文章 · 获赞 77 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/wodemaoheise/article/details/104949905
今日推荐