P1259 黑白棋子的移动【递归】

题目描述

有2n个棋子(n≥4)排成一行,开始为位置白子全部在左边,黑子全部在右边,如下图为n=5的情况:

○○○○○●●●●●

移动棋子的规则是:每次必须同时移动相邻的两个棋子,颜色不限,可以左移也可以右移到空位上去,但不能调换两个棋子的左右位置。每次移动必须跳过若干个棋子(不能平移),要求最后能移成黑白相间的一行棋子。如n=5时,成为:

○●○●○●○●○●

任务:编程打印出移动过程。

输入格式

一个整数n(n<=100)

输出格式

若干行,表示初始状态和每次移动的状态,用"o"表示白子,"*"表示黑子,"-"表示空行。

输入输出样例

输入 

7

输出 

ooooooo*******--
oooooo--******o*
oooooo******--o*
ooooo--*****o*o*
ooooo*****--o*o*
oooo--****o*o*o*
oooo****--o*o*o*
ooo--***o*o*o*o*
ooo*o**--*o*o*o*
o--*o**oo*o*o*o*
o*o*o*--o*o*o*o*
--o*o*o*o*o*o*o*

解题思路

先仔细观察,我们可以发现,从初始字符串“ooooooo*******--”开始,处理两步后得到“oooooo******--o*”,该字符串实际是n=6的一个子问题,而对于每一个子问题n,其移动步骤是: //先将n,n+1移动到2n+1,2n+2的空位,再将2n-1,2n移动到n,n+1的空位。因此我们可以使用递归,不断将我们的问题化小,但是注意的是,当n==4其转移步骤有所不同,因此这里当n缩小为4时,我们需要单独处理(也可以说是递归的边界)。

代码

#include
#include
#include
using namespace std;

int str[220];     //3表示"o",2表示"*",1表示"-"
int n;

void print(int strat)   //打印从start开始到末尾的字符串
{
	for (int i = strat; i <= n * 2 + 2; i++)
	{
		if (str[i] == 3)
			printf("o");
		else if (str[i] == 2)
			printf("*");
		else if (str[i] == 1)
			printf("-");
	}
	printf("\n");
}


void fun(int n)     //n表示缩小为规模n的子问题
{
	if (n == 4)     //当n缩小为4时单独处理
	{
		printf("ooo--***o*");
		print(11);
		printf("ooo*o**--*");
		print(11);
		printf("o--*o**oo*");
		print(11);
		printf("o*o*o*--o*");
		print(11);
		printf("--o*o*o*o*");
		print(11);
	}
	else             //先将n,n+1移动到2n+1,2n+2的空位,再将2n-1,2n移动到n,n+1的空位
	{
		str[2 * n + 1] = str[n];
		str[2 * n + 2] = str[n + 1];
		str[n] = str[n + 1] = 1;
		print(1);
		str[n] = str[2 * n - 1];
		str[n + 1] = str[2 * n];
		str[2 * n - 1] = str[2 * n] = 1;
		print(1);
		fun(n - 1);   //缩小为n-1规模的问题
	}
}

int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		str[i] = 3;
	for (int i = n + 1; i <= 2 * n; i++)
		str[i] = 2;
	str[2 * n + 1] = str[2 * n + 2] = 1;
	print(1);
	fun(n);
	return 0;
}

 

你可能感兴趣的:(洛谷)