UVA-1601
阿新 • • 發佈:2020-09-10
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\)種,顯然是會超時的,所以有如下優化:
- 我們把每個點的可通行位置提取出來構成一張無向圖,在這張圖上跑bfs,每次我們只需要遍歷可 以到達的點。
- 對所有的空白格編號,搜尋針對編號處理。
- 雙向bfs搜尋,提高搜尋效率
- 對每種狀態可知,之多有三個鬼分佈在圖的不同位置,每個數最大為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,算是比較快的了