洛谷-P1259 黑白棋子的移动(基础分治)¶
题目描述¶
有2n个棋子(n≥4)排成一行,开始为位置白子全部在左边,黑子全部在右边,如下图为n=5的情况:
○○○○○●●●●●
移动棋子的规则是:每次必须同时移动相邻的两个棋子,颜色不限,可以左移也可以右移到空位上去,但不能调换两个棋子的左右位置。每次移动必须跳过若干个棋子(不能平移),要求最后能移成黑白相间的一行棋子。如n=5时,成为:
○●○●○●○●○●
任务:编程打印出移动过程。
输入格式¶
一个整数n(n<=100)
输出格式¶
若干行,表示初始状态和每次移动的状态,用"o"表示白子,"*"表示黑子,"-"表示空行。
输入输出样例¶
输入 #1
7
输出 #1
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*
#include <bits/stdc++.h>
using namespace std;
vector<char> seq(210);
int n;
int step = 0; //记录到了第几步
int pos; //记录空位的起始位置
void print()
{
//setiosflags(ios::right);
//cout << "step" << setw(2) << step << ":";
for (int i = 1; i <= 2 * n + 2; ++i) cout << seq[i];
cout << endl;
++step;
}
void init(int n)
{
pos = 2 * n + 1;
for (int i = 1; i <= n; ++i) seq[i] = 'o';
for (int i = n + 1; i <= 2 * n; ++i) seq[i] = '*';
seq[2 * n + 1] = seq[2 * n + 2] = '-';
print();
}
void move(int k)
{
std::swap(seq[k], seq[pos]);
std::swap(seq[k + 1], seq[pos + 1]);
pos = k;
print();
}
void solve(int n)
{
if (n == 4) {
move(4); move(8); move(2); move(7); move(1);
}
else {
move(n); move(2 * n - 1); solve(n - 1);
}
}
int main()
{
std::ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin >> n;
init(n);
solve(n);
return 0;
}
解析:首先分析n = 4的时候如何移动。(注--表示空位)
○○○○●●●●--
第一步:○○○--●●●○●
第二步:○○○●○●●--●
第三步:○--●○●●○○●
第四步:○●○●○●--○●
第五步:--○●○●○●○●
如果n = 5的时候,分析:
○○○○○●●●●●--
第一步:○○○○--●●●●○●
第二步:○○○○●●●●--○●
发现序列的前半部分恰好是n = 4的情况,于是发现n的移动可以在n-1的移动基础上构造。