洛谷题单指南-递推与递归-P1259 黑白棋子的移动
原题链接:https://www.luogu.com.cn/problem/P1259
题意解读:要打印最终的状态,关键在找到一些变化的规律,直接的暴力搜索复杂度太高。
解题思路:
从样例出发
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*
可以看到,当n = 7时,通过两步变化,可以得到n = 6的初始情况再加上一组o*
同样,当n = 6时,通过两步变化,可以得到n = 5的初始情况再加上一组o*
同理,当n = 5时,通过两步变化,可以得到n = 4的初始情况再加上一组o*
而当n = 4时,则没有上述规律,有特定的变化步骤来得到结果:
oooo****--
ooo--***o*
ooo*o**--*
o--*o**oo*
o*o*o*--o*
--o*o*o*o*
可以总结出,当n > 4时,总能通过同样的变化将问题缩小为处理n - 1、n - 2......一直到4的情况,进行特殊处理即可。
而当n > 4时,两步操作为:
1、将最后一个o、第一个*与空白处交换位置
2、将连续*的最后两个,与空白处交换位置
这样就得到了n - 1的情况,最后两个字符是o*
因此,完整的流程为:
1、初始化字符串
2、不断进行上述的两步操作,使得字符串前10个字符变成oooo****--,即n = 4
3、再针对n = 4的情况特殊处理
此题本质上是一个分治思想,具体细节请参考代码。
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 210;
string t[5] = {
"ooo--***o*",
"ooo*o**--*",
"o--*o**oo*",
"o*o*o*--o*",
"--o*o*o*o*"
};
char s[N];
int n;
//输出s字符串
void print()
{
for(int i = 1; i <= 2 * n + 2; i++) cout << s[i];
cout << endl;
}
int main()
{
cin >> n;
//初始化s字符串
for(int i = 1; i <= n; i++) s[i] = 'o';
for(int i = n + 1; i <= 2 * n; i++) s[i] = '*';
s[2 * n + 1] = s[2 * n + 2] = '-';
print();
int w = 2 * n + 1; //第一个空白位置
while(w != 9) { //多于2 * 4个棋子时
int lastO = (w - 1) / 2; //最后一个'o'的位置
swap(s[lastO], s[w]);
swap(s[lastO + 1], s[w + 1]);
print();
int lastS = w - 1;//连续'*'的最后一个位置
w = lastO; // 更新第一个空白所在位置
swap(s[lastS - 1], s[w]);
swap(s[lastS], s[w + 1]);
print();
w = lastS - 1;
}
//当w前面只有2 * 4个棋子时,特殊处理
for(int i = 0; i < 5; i++)
{
cout << t[i];
for(int j = 11; j <= 2 * n + 2; j += 2)
{
cout << "o*";
}
cout << endl;
}
return 0;
}