UVA-1601

The Morning after Halloween(UVA-1601)

Problem:https://vjudge.net/problem/UVA-1601

Input:

5 5 2
#####
#A#B#
#   #
#b#a#
#####
16 4 3
################
## ########## ##
#    ABCcba    #
################
16 16 3
################
### ##    #   ##
##  #  ##   # c#
#  ## ########b#
# ##  # #   #  #
#  # ##   # # ##
##  a#  # # #  #
### ## #### ## #
##   #   #  #  #
#  ##### # ## ##
####   #B# #   #
##  C#   #   ###
#  # # ####### #
# ######  A##  #
#        #    ##
################
0 0 0

Output:

7
36
77

Solution:

双向bfs经典题,这题的核心算法就是双向bfs,但是对于本题的优化是非常有趣的。在题中提出了没个2*2的方块里至少一个墙壁,所以可通行的地方最多有75%的方格,如果我们直接去搜图中的点,那么每个点需要检验五个状态,同时又有三个鬼,所以要遍历(5^3)种也就是125个,同时有((16 *16)^3)种状态也就是(256^3)种,显然是会超时的,所以有如下优化:

  1. 我们把每个点的可通行位置提取出来构成一张无向图,在这张图上跑bfs,每次我们只需要遍历可 以到达的点。
  2. 对所有的空白格编号,搜索针对编号处理。
  3. 双向bfs搜索,提高搜索效率
  4. 对每种状态可知,之多有三个鬼分布在图的不同位置,每个数最大为192(图上空白格数,实际会更小),所以应一个三位的192进制数表示即可(整数哈希)。

代码实际写起来会有些不好处理的地方,由于本人较菜,所以代码比较长。大佬可以自行优化orz。

Code:

/**********************************************************
* @Author: 			   Kirito
* @Last Modified by:   Kirito
* @Remark:
**********************************************************/
#include <bits/stdc++.h>
#define lowbit(x) (x&(-x))
#define CSE(x,y) memset(x,y,sizeof(x))
#define INF 0x3f3f3f3f
#define Abs(x) (x>=0?x:(-x))
#define FAST ios::sync_with_stdio(false);cin.tie(0);
#define debug(x) cout<<#x<<"------"<<x<<endl
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll , ll> pll;

const int MAXN=31;
const int mv[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int w,h,n;
string str[MAXN];
pii ls[MAXN*MAXN];
int cnt;
vector<int> gp[202];

struct node{
    int ad0,ad1,ad2;
    int step;
    node(int x=0,int y=0,int z=0,int d=1):ad0(x),ad1(y),ad2(z),step(d){}

    int getHash(){
        return ad0+ad1*256+ad2*256*256;
    }
}be,ed;

int vis[8000000],vit[8000000];
int bfs()
{
    queue<node> box,que;
    if(be.getHash()==ed.getHash()) return 0;
    vis[be.getHash()]=1;
    vit[ed.getHash()]=1;
    box.push(be);que.push(ed);
    while(!box.empty()&&!que.empty()){
        if(box.size()<que.size()){
            int ok=box.front().step;
            while(!box.empty()&&ok==box.front().step){
                node now=box.front();
                box.pop();
                for(auto i:gp[now.ad0]){
                    if(n>1){
                        for(auto j:gp[now.ad1]){
                            if(i==j) continue;
                            if(i==now.ad1&&j==now.ad0) continue;
                            if(n>2){
                                for(auto k:gp[now.ad2]){
                                    if(i==k||j==k) continue;
                                    if(i==now.ad2&&k==now.ad0) continue;
                                    if(j==now.ad2&&k==now.ad1) continue;
                                    node nxt=node(i,j,k,now.step+1);
                                    int hh=nxt.getHash();
                                    if(vis[hh]) continue;
                                    if(vit[hh]){
                                        return nxt.step+vit[hh]-2;
                                    }
                                    vis[hh]=nxt.step;
                                    box.push(nxt);
                                }
                            }
                            else{
                                node nxt=node(i,j,0,now.step+1);
                                int hh=nxt.getHash();
                                if(vis[hh]) continue;
                                if(vit[hh]){
                                    return nxt.step+vit[hh]-2;
                                }
                                vis[hh]=nxt.step;
                                box.push(nxt);
                            }
                        }
                    }
                    else{
                        node nxt=node(i,0,0,now.step+1);
                        int hh=nxt.getHash();
                        if(vis[hh]) continue;
                        if(vit[hh]){
                            return nxt.step+vit[hh]-2;
                        }
                        vis[hh]=nxt.step;
                        box.push(nxt);
                    }
                }
            }
        }
        else{
            int ok=que.front().step;
            while(!que.empty()&&ok==que.front().step){
                node now=que.front();
                que.pop();
                for(auto i:gp[now.ad0]){
                    if(n>1){
                        for(auto j:gp[now.ad1]){
                            if(i==j) continue;
                            if(i==now.ad1&&j==now.ad0) continue;
                            if(n>2){
                                for(auto k:gp[now.ad2]){
                                    if(i==k||j==k) continue;
                                    if(i==now.ad2&&k==now.ad0) continue;
                                    if(j==now.ad2&&k==now.ad1) continue;
                                    node nxt=node(i,j,k,now.step+1);
                                    int hh=nxt.getHash();
                                    if(vit[hh]) continue;
                                    if(vis[hh]){
                                        return nxt.step+vis[hh]-2;
                                    }
                                    vit[hh]=nxt.step;
                                    que.push(nxt);
                                }
                            }
                            else{
                                node nxt=node(i,j,0,now.step+1);
                                int hh=nxt.getHash();
                                if(vit[hh]) continue;
                                if(vis[hh]){
                                    return nxt.step+vis[hh]-2;
                                }
                                vit[hh]=nxt.step;
                                que.push(nxt);
                            }
                        }
                    }
                    else{
                        node nxt=node(i,0,0,now.step+1);
                        int hh=nxt.getHash();
                        if(vit[hh]) continue;
                        if(vis[hh]){
                            return nxt.step+vis[hh]-2;
                        }
                        vit[hh]=nxt.step;
                        que.push(nxt);
                    }
                }
            }
        }
    }
    return -1;
}

int main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.in","r",stdin);
	#endif
    while(cin>>w>>h>>n){
        if(w==0&&h==0&&n==0) break;
        cin.get();
        for(int i=0;i<h;i++){
            getline(cin,str[i]);
        }
        cnt=0;
        be=node();ed=node();
        ls[cnt++]=make_pair(0,0);
        for(int i=0;i<h;i++){
            for(int j=0;j<w;j++){
                if(str[i][j]!='#'){
                    ls[cnt++]=make_pair(i,j);
                }
            }
        }
        sort(ls,ls+cnt);
        for(int i=0;i<200;i++)
            gp[i].clear();
        for(int i=0;i<h;i++){
            for(int j=0;j<w;j++){
                if(str[i][j]!='#'){
                    int u=int(lower_bound(ls,ls+cnt,make_pair(i,j))-ls);
                    if(str[i][j]>='A'&&str[i][j]<='Z'){
                        int m=int(str[i][j]-'A');
                        if(m==0) ed.ad0=u;
                        else if(m==1) ed.ad1=u;
                        else ed.ad2=u;
                    }
                    if(str[i][j]>='a'&&str[i][j]<='z'){
                        int m=int(str[i][j]-'a');
                        if(m==0) be.ad0=u;
                        else if(m==1) be.ad1=u;
                        else be.ad2=u;
                    }
                    gp[u].push_back(u);
                    for(int k=0;k<4;k++){
                        int nx=i+mv[k][0];
                        int ny=j+mv[k][1];
                        if(nx>=0&&nx<h&&ny>=0&&ny<w&&str[nx][ny]!='#'){
                            int v=int(lower_bound(ls,ls+cnt,make_pair(nx,ny))-ls);
                            gp[u].push_back(v);
                        }
                    }
                }
            }
        }
        CSE(vis,0);CSE(vit,0);
        cout<<bfs()<<endl;
    }
	return 0;
}

我这份代码跑了560ms,算是比较快的了

原文地址:https://www.cnblogs.com/LeafLove/p/13647364.html