USACO穿梭谜题(DFS)

大小为 3 的穿梭谜题由三个白石子三个黑石子和带着七个孔的木板组成。

最初,将白石子放在木板左端的孔中,黑石子放在右端的孔中,中间的孔空着。

最终,要将白石子移动到右端,将黑石子移动到左端。

初始状态:WWW_BBB
最终状态:BBB_WWW
在解决这一问题时,共有两种移动石子的方法:

将一个石子移动至相邻的空孔之中。
将一个石子跳过一个与它不同色的石子,移动至空孔之中。
石子不能往回走,也不能一次跳过两个或以上的石子。

一个大小为 N 的穿梭谜题,应该由 N 个白石子,N 个黑石子以及有 2N+1 个空孔的木板组成。

下面是大小为 3 的穿梭谜题的一种解决方案,显示了初始、中间、结束状态:

WWW BBB
WW WBBB
WWBW BB
WWBWB B
WWB BWB
W BWBWB
WBWBWB
BW WBWB
BWBW WB
BWBWBW
BWBWB W
BWB BWW
B BWBWW
BB WBWW
BBBW WW
BBB WWW
找到移动步数最少的解决问题的方案。

输入格式
共一行,包含一个整数 N。

输出格式
我们将木板的 2N+1 个孔从左到右依次编号为 1∼2N+1。

我们需要输出移动步数最少的解决方案。

假设这个方案共需移动 S 步,那么我们就需要输出 S 个整数。

其中,第 i 个整数表示第 i 步方案要移动的棋子在移动前的位置编号。

如果存在多个最佳方案,则输出答案序列字典序最小的那个。

注意,输出时每行最多包含 20 个数。

数据范围
1≤N≤12
输入样例:
3
输出样例:
3 5 6 4 2 1 3 5 7 6 4 2 3 5 4
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 10000;

int n;
int ans[N], top = N;
int path[N];
string state, target;

void dfs(int p, int k)
{
    
    
    if (k >= top) return;
    if (state == target) //第一次更新就是最小字典序
    {
    
    
        memcpy(ans, path, k * 4);
        top = k;
        return;
    }
    if (p - 2 >= 0 && state[p - 2] == 'W' && state[p - 1] == 'B')//wb_
    {
    
    
        path[k] = p - 2;
        swap(state[p - 2], state[p]);
        dfs(p - 2, k + 1);
        swap(state[p - 2], state[p]);
    }
    if (p - 1 >= 0 && state[p - 1] == 'W')//w_
    {
    
    
        path[k] = p - 1;
        swap(state[p - 1], state[p]);
        dfs(p - 1, k + 1);
        swap(state[p - 1], state[p]);
    }
    if (p + 1 <= n * 2 && state[p + 1] == 'B')//_b
    {
    
    
        path[k] = p + 1;
        swap(state[p + 1], state[p]);
        dfs(p + 1, k + 1);
        swap(state[p + 1], state[p]);
    }
    if (p + 2 <= n * 2 && state[p + 2] == 'B' && state[p + 1] == 'W')//_wb
    {
    
    
        path[k] = p + 2;
        swap(state[p + 2], state[p]);
        dfs(p + 2, k + 1);
        swap(state[p + 2], state[p]);
    }
}

int main()
{
    
    
    cin >> n;
    state = string(n, 'W') + ' ' + string(n, 'B');
    target = state;
    reverse(target.begin(), target.end());
    dfs(n, 0);//第一个空格的位置在n位置上

    for (int i = 0; i < top; i ++ )
    {
    
    
        cout << ans[i] + 1;
        if ((i + 1) % 20 == 0) cout << endl;
        else cout << ' ';
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43738331/article/details/112797641