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<iostream>
#include<cstdio>
#include<string>
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;
}

浙公网安备 33010602011771号