題解 luogu P2083 【找人】
阿新 • • 發佈:2018-12-02
蒟蒻學完並查集,看啥都是並查集。
於是我就神奇的用並查集解出了此題
思路就是從1至n*
m掃一圈,將當前房間所在位置與它指向房間merge注意必須把它merge到它指向房間的兒子節點。最後,你就會發現同學家正好是一個根節點
樣例merge後樣子如下,但樣例中無死迴圈情況,這題是可能出現小明反覆繞圈的情況的,所以我們要判定一下。
2,3
3,3 2,1
1,2 1,3
3,3 1,1
2,2 3,1
我們選取的儲存方式為並查集中的 建立補集法
m為第二層,以此類推,所以,並查集陣列要有100000個
還有此題中切記不可用路徑壓縮,不然就無法完美重現找的過程。
程式碼如下
#include<bits/stdc++.h> using namespace std; int b[1005][100][3]; int bcj[99999999]; int hp=0,n,m,v,t=0,o=0; void fget(int x) { if (x/m!=bcj[x]/m)hp+=abs(bcj[x]/m-x/m)*v; if (bcj[x]==x)return; else fget(bcj[x]);//這裡是重現找的部分,只比標準的找多一行家HP } int get(int x) { o++; if (o>n*m) {o=0;return 2147483647;}//若進入了死迴圈,跳出 if (bcj[x]==x){o=0;return x;} else return get(bcj[x]); //並查集標準找的部分,注意沒有路徑壓縮哦 } void merge(int x,int y) { bcj[x]=y;//不要連線到Y節點的樹根部分要連線到最下面 } int main() { int i,j,x,y,ans=2147483647,k; cin>>n>>m>>v>>x>>y; for (i=1;i<=n*m;i++)bcj[i]=i; for (i=1;i<=n;i++) for (j=1;j<=m;j++) cin>>b[i][j][1]>>b[i][j][2];//每層使用者的提供資訊 for (i=1;i<=n;i++) for (j=1;j<=m;j++) { merge((i-1)*m+j,(b[i][j][1]-1)*m+b[i][j][2]);//合併部分,(i-1)*m+j為當前使用者所在的i層第j間房,後面同理,不過是指向當前房間指向位置 } for (i=1;i<=m;i++) { if (get(i)==(x-1)*m+y) {fget(i);if (hp<ans)ans=hp;hp=0;}//若根節點為同學家,找,替換最小值 } if (ans==2147483647)cout<<"impossible"; else cout<<ans;//輸出 return 0; }
撒花結束