USACO-Section 4.4 Shuttle Puzzle (BFS)

本文介绍了使用BFS解决USACO中3x棋盘游戏的策略,探讨了游戏规则、有效移动及如何寻找最少移动步数的解决方案。在3x棋盘游戏中,通过比较与魔板和八数码问题的相似性,提出了BFS作为求解方法,同时指出在实现过程中需要注意避免无效状态的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述

大小为3的棋盘游戏里有3个白色棋子,3个黑色棋子,和一个有7个格子一线排开的木盒子。3个白棋子被放在一头,3个黑棋子被放在另一头,中间的格子空着。

初始状态: WWW_BBB 
目标状态: BBB_WWW

在这个游戏里有两种移动方法是允许的:

  1. 你可以把一个棋子移到与它相邻的空格;
  2. 你可以把一个棋子跳过一个(仅一个)与它不同色的棋子到达空格。

大小为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的棋盘游戏(1 <= N <= 12)。要求用最少的移动步数实现。

格式

PROGRAM NAME: shuttle

INPUT FORMAT:

(file shuttle.in)

一个整数N。

OUTPUT FORMAT:

(file shuttle.out)

输出用移动的棋子在棋盘的位置(位置从左到右依次为1, 2, ..., 2N+1)表示的变换序列,每个数字之间以空格分隔,每行20个数(除了最后一行)。

输出的解还应当有最小的字典顺序(即如果有多组移动步数最小的解,输出第一个数最小的解;如果还有多组,输出第二个数最小的解;...)。

SAMPLE INPUT

3

SAMPLE OUTPUT

3 5 6 4 2 1 3 5 7 6 4 2 3 5 4

感觉这这种题和 魔板 与 八数码 差不多,轻易就能想到bfs

又是太依赖map了,感觉不用map就TLE了(只是按照要求写了互换的操作,并且指定B只能左移,W只能右移,但是还存在大量的无效状态,例如:空的一边有两个相同的W或B时,且在其外侧还有另一种字符(B或W),则无法达到最终状态)


/*
ID: your_id_here
PROG: shuttle
LANG: C++
*/
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <algorithm>

using namespace std;

struct Node {
    int i,pre;
    char s[27];

    Node() {
        memset(s,0,sizeof(s));
    }

    bool operator < (const Node& x) const {
        return strcmp(s+1,x.s+1)<0;
    }

    bool operator == (const Node& x) const {
        return strcmp(s+1,x.s+1)==0;
    }
}sta,des,u,v,q[100005];

int n,head,tail,ans[100005],cnt=0;
char ch;
map<Node,int> indx;

void bfs() {
    head=tail=1;
    q[tail++]=sta;
    indx[sta]=head;

    while(head!=tail) {
        u=q[head++];
        if(u.i>2&&u.s[u.i-1]=='B'&&u.s[u.i-2]=='W') {//W隔一个B跳到空
            v=u;
            v.s[v.i-2]=' ';
            v.s[v.i]='W';
            v.i-=2;
            v.pre=indx[u];
            if(indx[v]==0) {
                if(v==des) {
                    des.pre=v.pre;
                    return ;
                }
                q[tail]=v;
                indx[v]=tail++;
            }
        }
        if(u.i>1&&u.s[u.i-1]=='W') {//W跳到相邻的空
            v=u;
            v.s[v.i-1]=' ';
            v.s[v.i]='W';
            --v.i;
            v.pre=indx[u];
            if(indx[v]==0) {
                if(v==des) {
                    des.pre=v.pre;
                    return ;
                }
                q[tail]=v;
                indx[v]=tail++;
            }
        }
        if(u.i<n&&u.s[u.i+1]=='B') {//B跳到相邻的空
            v=u;
            v.s[v.i+1]=' ';
            v.s[v.i]='B';
            ++v.i;
            v.pre=indx[u];
            if(indx[v]==0) {
                if(v==des) {
                    des.pre=v.pre;
                    return ;
                }
                q[tail]=v;
                indx[v]=tail++;
            }
        }
        if(u.i<n-1&&u.s[u.i+1]=='W'&&u.s[u.i+2]=='B') {//B隔一个W跳到空
            v=u;
            v.s[v.i+2]=' ';
            v.s[v.i]='B';
            v.i+=2;
            v.pre=indx[u];
            if(indx[v]==0) {
                if(v==des) {
                    des.pre=v.pre;
                    return ;
                }
                q[tail]=v;
                indx[v]=tail++;
            }
        }
    }
}

void print() {
    while(des.pre!=-1) {
        ans[cnt++]=des.i;
        des=q[des.pre];
    }
    int tmp=0;
    while(cnt>1) {
        printf("%d",ans[--cnt]);
        if(++tmp==20) {
            tmp=0;
            printf("\n");
        }
        else
            printf(" ");
    }
    printf("%d\n",ans[0]);
}

int main() {
    freopen("shuttle.in","r",stdin);
    freopen("shuttle.out","w",stdout);

    scanf("%d",&n);
    sta.pre=-1;
    sta.i=des.i=n+1;
    sta.s[n+1]=des.s[n+1]=' ';
    for(int i=1;i<=n;++i) {
        sta.s[i]=des.s[n+1+i]='W';
        des.s[i]=sta.s[n+1+i]='B';
    }
    n=(n<<1)+2;
    bfs();
    print();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值