洛谷题单指南-递推与递归-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;
}

 

posted @ 2024-02-20 17:12  五月江城  阅读(31)  评论(0编辑  收藏  举报