【BFS】蓝桥杯真题 2016初赛 卡片换位

题目描述

你玩过华容道的游戏吗?这是个类似的,但更简单的游戏。看下面 3 x 2 的格子

	+---+---+---+
    | A | * | * | 
    +---+---+---+
    | B |   | * |
    +---+---+---+

在其中放5张牌,其中A代表关羽,B代表张飞,* 代表士兵。还有一个格子是空着的。
你可以把一张牌移动到相邻的空格中去(对角不算相邻)。
游戏的目标是:关羽和张飞交换位置,其它的牌随便在哪里都可以。

输入

输入存在多组测试数据,对于每组测试数据:
输入两行6个字符表示当前的局面

输出

对于每组测试数据输出一个整数表示答案

样例输入

* A
**B
A B
***

样例输出

17
12



思路

     这是一道你一眼看不出他想让你干啥的题目,是让你求最短路径呢,还是让你求能交换位置的方案数,经过多次实践,事实告诉我这是在求最短路径=_=
     做题思路:
1、利用gets()读取带有空格的字符串
2、每个星号*都是不一样的,要区分,不然答案会不对
3、利用字符串存储每个状态,某个字符位置是i,上下左右就是i-3, i+3, i-1,i+1,特定位置要特殊判断
4、利用vis记录是否遍历过某状态,避免重复进入死循环
5、最短路径就是bfs,具体见代码,有注释



代码

#include<bits/stdc++.h>
using namespace std;

//判断A和B是否已经交换位置
bool check(string &s, int a, int b){
    int flag = 0;
    for(int i=0; i<s.size(); i++){
        if(s[i]=='A' && i==b)
            flag++;

        if(s[i]=='B' && i==a)
            flag++;
    }

    return flag==2;
}

int main(){
    char s[2][3];
    while(gets(s[0])){
        //记录路径是否已经被走过
        map<string, int> vis;

        //记录最小步数
        int ans = 0;

        gets(s[1]);

        string a;

        //cnt记录*号,每个*号都不一样
        int apos, bpos, cnt = 0;

        //将输入转化为一个字符串,空格' '和'A' 'b'不变,将*转化为0 1 2 3...
        for(int i=0; i<2; i++){
            for(int j=0; j<3; j++){
                if(s[i][j]=='*'){
                    a += cnt + '0';
                    cnt++;
                }
                else
                    a += s[i][j];

                if(s[i][j]=='A')
                    apos = i*3+j;

                if(s[i][j]=='B')
                    bpos = i*3 + j;
            }
        }

        //标志初始状态已遍历过
        vis[a] = 1;

        queue<string> que;
        que.push(a);
        int flag = 0;

        while(que.size()){
            int n = que.size();

            while(n--){
                string t = que.front();
                que.pop();

                int pos;
                flag = 0;

                for(int i=0; i<6; i++){
                    if(t[i]==' '){
                        pos = i;
                        break;
                    }
                }

                //上
                if(pos-3>=0){
                    string tmp = t;
                    swap(tmp[pos], tmp[pos-3]);

                    if(check(tmp, apos, bpos)){
                        flag = 1;
                        break;
                    }else if(!vis[tmp]){
                        que.push(tmp);
                        vis[tmp] = 1;
                    }

                }

                //下
                if(pos+3<6){
                    string tmp = t;
                    swap(tmp[pos], tmp[pos+3]);


                    if(check(tmp, apos, bpos)){
                        flag = 1;
                        break;
                    }else if(!vis[tmp]){
                        que.push(tmp);
                        vis[tmp] = 1;
                    }
                }

                //左
                if(pos-1>=0 && pos!=3){
                    string tmp = t;
                    swap(tmp[pos], tmp[pos-1]);


                    if(check(tmp, apos, bpos)){
                        flag = 1;
                        break;
                    }else if(!vis[tmp]){
                        que.push(tmp);
                        vis[tmp] = 1;
                    }
                }

                //右
                if(pos+1<6 && pos!=2){
                    string tmp = t;
                    swap(tmp[pos], tmp[pos+1]);

                    if(check(tmp, apos, bpos)){
                        flag = 1;
                        break;
                    }else if(!vis[tmp]){
                        que.push(tmp);
                        vis[tmp] = 1;
                    }
                }
            }
            ans++;

            if(flag)
                break;
        }
        cout<<ans<<endl;
    }


    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值