高質量好題:ARC118D
阿新 • • 發佈:2021-08-11
儲存一些沒有那麼難的搜尋題目。
小明的遊戲
是通過圖論標籤找到它的,結果它是一個搜尋題?
怎麼說呢,圖論的外表,搜尋的內心。
從圖論的角度來想,那就是對於 \(Dijkstra\) 堆優化部分的進一步優化。由於邊權 \(val\in{0,1}\) ,那麼在堆中只會有兩種 \(dis\) 的結點。考慮用雙端佇列優化這個部分。
從搜尋的角度來想,如果它和國際象棋一樣是交替的(也就是說它每走一步邊權都是1),那麼這就是當年學搜尋的題目了,直接用一個佇列就可以實現廣搜。但問題是它的邊權還有可能是0,那麼我們就需要“更加高階”的佇列,也就是雙端佇列。
兩種思路實現方法一樣,如果擴充套件的一個節點,它不比隊首大,就丟到前面;反之,丟到隊尾。這樣就可以保持佇列內部的單調性,就可以順利完成轉移。
一如既往,萬事勝意#include<cstdio> #include<cstring> #include<deque> //#define zczc using namespace std; const int N=510; inline void read(int &wh){ wh=0;int f=1;char w=getchar(); while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();} while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); } wh*=f;return; } inline bool get(){ char w=getchar(); while(w!='#'&&w!='@')w=getchar(); return w=='#'; } int m,n,fx,fy,ex,ey; bool a[N][N]; bool entering(){ read(m);read(n); if(m==0&&n==0)return false; for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ a[i][j]=get(); } } read(fx);read(fy);read(ex);read(ey); fx++,fy++,ex++,ey++; return true; } int an[N][N],f[4][2]={{0,1},{0,-1},{1,0},{-1,0}}; bool vis[N][N]; struct node{ int x,y,dis; }; deque<node>q; inline void add(node wh){ if(q.empty()||wh.dis<=q.front().dis)q.push_front(wh); else q.push_back(wh);return; } inline bool check(int x,int y){ return x<1||y<1||x>m||y>n; } void solve(){ memset(an,0x3f,sizeof(an)); memset(vis,false,sizeof(vis)); while(!q.empty())q.pop_front(); an[fx][fy]=0; add((node){fx,fy,0}); while(!q.empty()){ node now=q.front();q.pop_front(); int nx=now.x,ny=now.y,nd=now.dis; if(nx==ex&&ny==ey){ printf("%d\n",now.dis); return; } if(vis[nx][ny])continue;vis[nx][ny]=true; for(int i=0;i<4;i++){ int rx=nx+f[i][0],ry=ny+f[i][1]; if(check(rx,ry))continue; if(an[nx][ny]+(a[nx][ny]^a[rx][ry])<an[rx][ry]){ an[rx][ry]=an[nx][ny]+(a[nx][ny]^a[rx][ry]); add((node){rx,ry,an[rx][ry]}); } } } return; } signed main(){ #ifdef zczc freopen("in.txt","r",stdin); #endif while(entering())solve(); return 0; }