uva 1601(单向bfs 双向bus 矩阵转图)

题意

在这里插入图片描述
在这里插入图片描述
不能走到一起,或者穿着走,

将矩阵转化成图,双向比单向优化300+ms

单向bfs

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

char l[20][20];
int num[20][20],g[200][6],vis[200][200][200],s[26],t[26];

struct node
{
    int a,b,c;
    int cnt;
    node(){};
    node(int a,int b,int c,int cnt): a(a),b(b),c(c),cnt(cnt){}
};

void bfs()
{
    int a1,b1,c1;
    memset(vis,0,sizeof vis);
    vis[s[0]][s[1]][s[2]] = 1;
    queue<node> q;
    node e;
    e.a = s[0],e.b = s[1],e.c = s[2],e.cnt = 0;
    q.push(e);
    while(!q.empty()){
        e = q.front();q.pop();
        if(e.a == t[0] && e.b == t[1] && e.c == t[2]){
            cout << e.cnt << endl;
            return ;
        }
        for(int i = 0 ; i <= g[e.a][0];i++){
            a1 = (i == 0 ? e.a:g[e.a][i]); //0的时候原地不动
            for(int j = 0 ; j <= g[e.b][0];j++){
                b1 = (j == 0 ? e.b:g[e.b][j]);
                for(int k = 0 ; k <= g[e.c][0];k++){
                    c1 = (k == 0 ? e.c:g[e.c][k]);
                    if(vis[a1][b1][c1]) continue;
                    //不能在同一个点上
                    if((a1 && b1 && a1 == b1) || (a1 && c1 && a1 == c1) || (b1 && c1 && b1 == c1)) continue;
                    //不能穿过字母走
                    if(a1 && b1 && a1 == e.b && b1 == e.a) continue;
                    if(a1 && c1 && a1 == e.c && c1 == e.a) continue;
                    if(b1 && c1 && b1 == e.c && c1 == e.b) continue;

                    vis[a1][b1][c1] = 1;
                    q.push(node(a1,b1,c1,e.cnt+1));
                }
            }
        }
    }
}

int main()
{
    int w,h,n;
    while(cin >> w >> h >> n && w + h + n){
        getchar();
        for(int i = 0 ; i < h ; i++){
            fgets(l[i],20,stdin);
        }

        //建图
        //给图中的空白处编号
        memset(num,0,sizeof num);
        int cnt = 0;
        for(int i = 0 ; i < h ; i++)
            for(int j = 0 ; j < w ; j++)
                if(l[i][j] != '#')
                    num[i][j] = ++cnt;
        //邻接表存图
        memset(g,0,sizeof g);
        for(int i = 0 ; i < h ; i++){
            for(int j = 0 ; j < w ; j++){
                if(num[i][j]){
                    int pos = num[i][j];
                    if(num[i+1][j]) g[pos][++g[pos][0]] = num[i+1][j];
                    if(num[i-1][j]) g[pos][++g[pos][0]] = num[i-1][j];
                    if(num[i][j+1]) g[pos][++g[pos][0]] = num[i][j+1];
                    if(num[i][j-1]) g[pos][++g[pos][0]] = num[i][j-1];
                }
            }
        }

        //找到初始状态和最终状态
        memset(s,0,sizeof s);
        memset(t,0,sizeof t);
        for(int i = 0 ; i < h ; i++){
            for(int j = 0 ; j < w ; j++){
                if(islower(l[i][j])) s[l[i][j] - 'a'] = num[i][j];
                else if(isupper(l[i][j])) t[l[i][j] - 'A'] = num[i][j];
            }
        }
        int m = 0;
        for(int i = 0 ; i < 26 ; i++){
            if(s[i]) s[m] = s[i],t[m++]=t[i];
        }
        if(n < 3) s[2] = 0,t[2] = 0;
        if(n < 2) s[1] = 0,t[1] = 0;

        bfs();

    }

    return 0;
}

双向bfs

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

char l[20][20];
int num[20][20],g[200][6],s[26],t[26];
int vis[200][200][200],vis1[200][200][200];

struct node
{
    int a,b,c;
    int cnt;
    node(){};
    node(int a,int b,int c,int cnt): a(a),b(b),c(c),cnt(cnt){}
};

void bfs()
{
    int a1,b1,c1;
    memset(vis,0,sizeof vis);
    memset(vis1,0,sizeof vis1);
    vis[s[0]][s[1]][s[2]] = 1;
    vis1[t[0]][t[1]][t[2]] = 1;
    queue<node> q;
    queue<node> w;
    node e,r;
    q.push(node(s[0],s[1],s[2],1));
    w.push(node(t[0],t[1],t[2],1));
    while(!q.empty() && !w.empty()){
        e = q.front();q.pop();
        r = w.front();w.pop();
        if(vis[r.a][r.b][r.c]){
            cout << vis1[r.a][r.b][r.c] + vis[r.a][r.b][r.c] - 2 << endl;
            return ;
        }
        else if(vis1[e.a][e.b][e.c]){
            cout << vis1[e.a][e.b][e.c] + vis[e.a][e.b][e.c] - 2<< endl;
            return;
        }

        for(int i = 0 ; i <= g[e.a][0];i++){
            a1 = (i == 0 ? e.a:g[e.a][i]); //0的时候原地不动
            for(int j = 0 ; j <= g[e.b][0];j++){
                b1 = (j == 0 ? e.b:g[e.b][j]);
                for(int k = 0 ; k <= g[e.c][0];k++){
                    c1 = (k == 0 ? e.c:g[e.c][k]);
                    if(vis[a1][b1][c1]) continue;
                    //不能在同一个点上
                    if((a1 && b1 && a1 == b1) || (a1 && c1 && a1 == c1) || (b1 && c1 && b1 == c1)) continue;
                    //不能穿过字母走
                    if(a1 && b1 && a1 == e.b && b1 == e.a) continue;
                    if(a1 && c1 && a1 == e.c && c1 == e.a) continue;
                    if(b1 && c1 && b1 == e.c && c1 == e.b) continue;

                    vis[a1][b1][c1] = e.cnt+1;
                    q.push(node(a1,b1,c1,e.cnt+1));
                }
            }
        }

        for(int i = 0 ; i <= g[r.a][0];i++){
            a1 = (i == 0 ? r.a:g[r.a][i]); //0的时候原地不动
            for(int j = 0 ; j <= g[r.b][0];j++){
                b1 = (j == 0 ? r.b:g[r.b][j]);
                for(int k = 0 ; k <= g[r.c][0];k++){
                    c1 = (k == 0 ? r.c:g[r.c][k]);
                    if(vis1[a1][b1][c1]) continue;
                    //不能在同一个点上
                    if((a1 && b1 && a1 == b1) || (a1 && c1 && a1 == c1) || (b1 && c1 && b1 == c1)) continue;
                    //不能穿过字母走
                    if(a1 && b1 && a1 == r.b && b1 == r.a) continue;
                    if(a1 && c1 && a1 == r.c && c1 == r.a) continue;
                    if(b1 && c1 && b1 == r.c && c1 == r.b) continue;

                    vis1[a1][b1][c1] = r.cnt+1;
                    w.push(node(a1,b1,c1,r.cnt+1));
                }
            }
        }
    }
}

int main()
{
    int w,h,n;
    while(cin >> w >> h >> n && w + h + n){
        getchar();
        for(int i = 0 ; i < h ; i++){
            fgets(l[i],20,stdin);
        }

        //建图
        //给图中的空白处编号
        memset(num,0,sizeof num);
        int cnt = 0;
        for(int i = 0 ; i < h ; i++)
            for(int j = 0 ; j < w ; j++)
                if(l[i][j] != '#')
                    num[i][j] = ++cnt;
        //邻接表存图
        memset(g,0,sizeof g);
        for(int i = 0 ; i < h ; i++){
            for(int j = 0 ; j < w ; j++){
                if(num[i][j]){
                    int pos = num[i][j];
                    if(num[i+1][j]) g[pos][++g[pos][0]] = num[i+1][j];
                    if(num[i-1][j]) g[pos][++g[pos][0]] = num[i-1][j];
                    if(num[i][j+1]) g[pos][++g[pos][0]] = num[i][j+1];
                    if(num[i][j-1]) g[pos][++g[pos][0]] = num[i][j-1];
                }
            }
        }

        //找到初始状态和最终状态
        memset(s,0,sizeof s);
        memset(t,0,sizeof t);
        for(int i = 0 ; i < h ; i++){
            for(int j = 0 ; j < w ; j++){
                if(islower(l[i][j])) s[l[i][j] - 'a'] = num[i][j];
                else if(isupper(l[i][j])) t[l[i][j] - 'A'] = num[i][j];
            }
        }
        int m = 0;
        for(int i = 0 ; i < 26 ; i++){
            if(s[i]) s[m] = s[i],t[m++]=t[i];
        }
        if(n < 3) s[2] = 0,t[2] = 0;
        if(n < 2) s[1] = 0,t[1] = 0;

        bfs();

    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值