例题7-9 UVA - 1601 && POJ 3523 The Morning after Halloween (双向BFS)

23 篇文章 0 订阅
12 篇文章 0 订阅

/*******************************************************

2017.1.26 --19:50

重新做了一遍这个题目。

其实一个单向的BFS 就可以过 920ms,思路和 原来的差不多,只不过改成了 结构体队列(用数组存的,数组肯定要比STL的queue 要快),里面的x[3] 存的是三只鬼的位置,这个位置xy坐标压缩成了一个整数,这个也是很好想的,xy坐标肯定小于16(最外面肯定是墙), 所以二进制最多4位, 这样二进制一组合,最多只有八位,不会超过256.

因此判重也就简单了, 用vis[256][256][256] 就可以了.

因为墙很多,空格很少,因此可以先给空格标号建立一张表   这样就又快了不少。

详细见代码:

最普通的bfs:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define Siz(x) (int)x.size()
using namespace std;
int n, m, r, g[3], hear, rear;
bool vis[256][256][256];
char s[20][20];
vector<int>G[260];
int id[20][20];
int mp[256];
const int dx[] = {1,-1,0,0,0};
const int dy[] = {0,0,-1,1,0};
bool isal(char& c){return c >= 'A' && c <= 'Z' && c >= 'a' && c <= 'z';}
bool isup(char& c){return c >= 'A' && c <= 'Z';}
bool islow(char& c){return c >= 'a' && c <= 'z';}
struct Node{
    int x[3];
    int d;
}p[5000000];
int code(int x,int y){ return (x << 4) | (y); }
int decode(int& x,int& y,int z){
    y = z % 16;
    z/=16;
    x = z;
}
int t[3],t2[3];
bool conf(int a,int b,int c,int d){
//    printf("%d -> %d , %d -> %d\n",a,b,c,d);
    if (b == d) return 1;
    if (a == d && b == c) return 1;
    return 0;



}
int bfs(){
    memset(vis,0,sizeof vis);
    vis[p[0].x[0] ][p[0].x[1] ][p[0].x[2] ] = 1;


    hear = 0, rear = 1;
    while(hear < rear){
        Node u = p[hear++];
//        for (int i = 0; i < 3; ++i) printf("%d ",u.x[i]);
//        puts("");
//        for (int i = 0; i < 3; ++i) printf("%d ",g[i]);
//        puts("");
        if (u.x[0] == g[0] && u.x[1] == g[1] && u.x[2] == g[2]) return u.d;
        for (int i = 0; i < Siz(G[u.x[0]]); ++i){
            int v0 = G[u.x[0] ][i];
            for (int j = 0; j < Siz(G[u.x[1]] ); ++j){
                int v1 = G[u.x[1] ][j];
                if (conf(u.x[0],v0,u.x[1],v1))continue;
                for (int k = 0; k < Siz(G[u.x[2] ]); ++k){
                    int v2 = G[u.x[2] ][k];
//                    printf("%d\n",v2);
//                    printf("%d %d %d\n",v0,v1,v2);
                    if (conf(u.x[0],v0,u.x[2],v2) || conf(u.x[1],v1,u.x[2],v2))continue;
                    if (!vis[v0][v1][v2]){
                        vis[v0][v1][v2] = 1;
                        p[rear].x[0] = v0;
                        p[rear].x[1] = v1;
                        p[rear].x[2] = v2;
                        p[rear].d = u.d + 1;
                        rear++;
                    }
                }
            }
        }
    }
    return -1;
}
int main() {
    while(~scanf("%d%d%d%*c",&m,&n,&r) && (n || m || r)){
        memset(p,0,sizeof p);
        for (int i = 0; i < 260; ++i){
            G[i].clear();
        }
        for (int i = 0; i < n; ++i){
            fgets(s[i],20,stdin);
        }
        int cnt=0;
        for (int i = 0; i < n; ++i){
            for (int j = 0; j < m; ++j){
                if (s[i][j] != '#'){
                    id[i][j] = cnt++;
                    mp[cnt-1] = code(i,j);
                    if (islow(s[i][j])){
                        p[0].x[s[i][j] -'a' ] = cnt-1;
                    }
                    else if (isup(s[i][j])){
                        g[s[i][j]-'A' ] = cnt-1;
                    }
                }
            }
        }
        for (int i = 0; i < cnt; ++i){
            int x,y;
            decode(x,y,mp[i]);
            for (int j = 0; j < 5; ++j){
                int xx = dx[j] + x;
                int yy = dy[j] + y;
                if (xx < n && xx >= 0 && yy < m && yy >= 0 && s[xx][yy] != '#'){
                    G[i].push_back(id[xx][yy]);
                }
            }
        }

//        for (int i = 0; i < cnt; ++i){
//            printf("%d:",i);
//            for (int j = 0; j < Siz(G[i]); ++j){
//                printf("%d ",G[i][j]);
//
//
//            }
//            puts("");
//
//
//        }

        if (r == 1){
            G[cnt].push_back(cnt);
            p[0].x[1] = cnt;
            g[1] = cnt++;
            G[cnt].push_back(cnt);
            p[0].x[2] = cnt;
            g[2] = cnt++;
        }
        else if (r == 2){
            G[cnt].push_back(cnt);
            p[0].x[2] = cnt;
            g[2] = cnt;
            cnt++;
        }
//        printf("%d\n",G[7][0]);
//        for (int i = 0; i < 3; ++i)printf("%d ",g[i]);
        printf("%d\n",bfs());
    }
    return 0;
}
/*
5 5 2
#####
#A#B#
# #
#b#a#
#####

*/


/******************************************************


大体题意:

你给一个h*w 的网格,网格上最多有三只小鬼,小鬼用小写字母abc 表示,他们的目标用ABC表示,问小鬼移动到目标最短的步数,他们可以同时走,走法有五种:上下左右和不动,其中有几种情况的走法是非法的:

1.两只小鬼一步以内交换了位置。

2.两只小鬼的下一步是同一个位置。

其余情况合法!


思路:

先将不是#的位置变成标号。

然后把所有空格提出来建立一张图,把初始位置的鬼存到s数组中,把鬼的目标位置存到t数组中。

然后以每个空格为中心 建立一张图G数组

然后把不够3个鬼的样例情况变成3个鬼。

然后开始双向bfs,正着走 vis 标记为1  反着走 标记为2

然后不断记录dis  走过的距离,  当正着走发现标记为2时返回dist 和

当反着走发现标记为1 时,返回dis和

说明一下  判断是否情况合法的函数:

bool config(int a,int b,int a2,int b2){
    return a2 == b2 || (a==b2 && b == a2);
}

四个参数   鬼1 的初始位置  鬼2 的初始位置 鬼1 的下一步位置  鬼2 的下一步位置。

当a2 == b2  也就是下一步走到同一个位置了  非法!

当(a==b2 && b == a2);  也就是一步以内交换位置了  非法!

int ID(int a,int b,int c){
    return (a<<16) | (b<<8) | c;
}

这个是对三个数进行编码  省了不少空间!

很极限的 代码 在POJ 真的就差一点点就爆内存了!

具体在看代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#define cin freopen("cin.txt","r",stdin);
using namespace std;
int w,h,n;
const int maxn = 200 + 1;
char mp[20][20];
int deg[maxn];
int dis[maxn][maxn][maxn];
int vis[maxn][maxn][maxn];
int s[3],t[3],G[maxn][5];
const int dx[] = {1,-1,0,0,0};
const int dy[] = {0,0,1,-1,0};
queue<int >qb,qf;
int ID(int a,int b,int c){
    return (a<<16) | (b<<8) | c;
}
bool config(int a,int b,int a2,int b2){
    return a2 == b2 || (a==b2 && b == a2);
}
bool init(int x,int y){
    return x >= 0 && x < h && y >= 0 && y < w;
}
int bfs(){
    memset(dis,0,sizeof dis);
    memset(vis,0,sizeof vis);
    while(!qb.empty())qb.pop();
    while(!qf.empty())qf.pop();
    vis[s[0]][s[1]][s[2]] = 1;
    vis[t[0]][t[1]][t[2]] = 2;
    dis[s[0]][s[1]][s[2]] = 0;
    dis[t[0]][t[1]][t[2]] = 1;
    qf.push(ID(s[0],s[1],s[2]));
    qb.push(ID(t[0],t[1],t[2]));
    while(!qb.empty() || !qf.empty()){
        int bnum = qb.size(),fnum = qf.size();
        while(!qb.empty()){
            int u = qb.front(); qb.pop();
            int a=(u>>16)&255,b=(u>>8)&255,c=u&255;
            for (int i = 0; i < deg[a]; ++i){
                int a2 = G[a][i];
                for (int j = 0; j < deg[b]; ++j){
                    int b2 = G[b][j];
                    if (config(a,b,a2,b2))continue;
                    for (int k = 0; k < deg[c]; ++k){
                        int c2 = G[c][k];
                        if (config(a,c,a2,c2) || config(b,c,b2,c2))continue;
                        if (vis[a2][b2][c2] == 0){
                            vis[a2][b2][c2] = 2;
                            dis[a2][b2][c2] = dis[a][b][c] + 1;
                            qb.push(ID(a2,b2,c2));
                        }
                        else if (vis[a2][b2][c2] == 1){
                            return dis[a2][b2][c2] + dis[a][b][c];
                        }
                    }
                }

            }

        }
        while(!qf.empty()){
            int u = qf.front(); qf.pop();
            int a=(u>>16)&255,b=(u>>8)&255,c=u&255;
            for (int i = 0; i < deg[a]; ++i){
                int a2 = G[a][i];
                for (int j = 0; j < deg[b]; ++j){
                    int b2 = G[b][j];
                    if (config(a,b,a2,b2))continue;
                    for (int k = 0; k < deg[c]; ++k){
                        int c2 = G[c][k];
                        if (config(a,c,a2,c2) || config(b,c,b2,c2))continue;
                        if (vis[a2][b2][c2] == 0){
                            vis[a2][b2][c2] = 1;
                            dis[a2][b2][c2] = dis[a][b][c] + 1;
                            qf.push(ID(a2,b2,c2));
                        }
                        else if (vis[a2][b2][c2] == 2){
                            return dis[a2][b2][c2] + dis[a][b][c];
                        }
                    }
                }

            }

        }

    }

}
int main(){
//    cin;
    while(scanf("%d%d%d",&w,&h,&n) == 3 && (w||h||n)){
        gets(mp[0]);
        for (int i = 0; i < h; ++i)gets(mp[i]);
        int cnt = 0,x[maxn],y[maxn],id[maxn][maxn];
        for (int i = 0; i < h; ++i){
            for (int j = 0; j < w; ++j){
                if (mp[i][j] != '#'){
                    x[cnt] = i;
                    y[cnt] = j;
                    id[i][j] = cnt;
                    char ch = mp[i][j];
                    if (islower(ch))s[ch-'a'] = cnt;
                    if (isupper(ch))t[ch-'A'] = cnt;
                    cnt++;
                }
            }
        }
        for (int i = 0; i < cnt; ++i){
            deg[i] = 0;
            for (int j = 0; j < 5; ++j){
                int xx = x[i] + dx[j];
                int yy = y[i] + dy[j];
                if (init(xx,yy) && mp[xx][yy] != '#')G[i][deg[i]++] = id[xx][yy];
            }
        }
        if (n <= 2) {
            deg[cnt] = 1;
            G[cnt][0] = cnt;
            s[2] = t[2] = cnt++;
            cnt++;
        }
        if (n <= 1) {
            deg[cnt] = 1;
            G[cnt][0] = cnt;
            s[1] = t[1] = cnt++;
        }
        if (s[0] == t[0] && s[1] == t[1] && s[2] == t[2])printf("0\n");
        else printf("%d\n",bfs());
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值