1. 程式人生 > 實用技巧 >UVA-1601

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,算是比較快的了