求圖中的最小環【洛谷P2661】
阿新 • • 發佈:2019-01-05
求有向圖中的最小環問題。
對於入度為0的點,肯定不在環內。我們就把入度為0的點刪掉。注意,刪掉入度為0的點,可能造成與之相鄰點的入度為0,我們就遞迴把聯通的結點全部刪掉。
然後對於每個環,我們遍歷所有剩下的環,儲存一個最小值就OK啦!
程式碼:
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5+7; const int INF = 1e9+7; int a[maxn]; int in[maxn]; bool vis[maxn]; int ans = INF; void remove(int s) { vis[s] = 1; in[a[s]]--; if(!in[a[s]] && !vis[a[s]]) { remove(a[s]); } } void dfs(int s,int e,int stp) { if(s==e && stp) { ans = min(ans,stp); return; } if(!vis[a[s]]) { vis[a[s]] = 1; dfs(a[s],e,stp+1); } } int main() { int n; cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; in[a[i]]++; } for(int i=1;i<=n;i++) { if(!in[i] && !vis[i]) { remove(i); } } for(int i=1;i<=n;i++) { if(!vis[i]) { dfs(i,i,0); } } cout<<ans<<endl; return 0; }
我去看看並查集求最小環,看會了把這個補上。
UPD:並查集做法大概看了一下,下面講並查集的做法:
並查集求有向圖最小環:
如果有兩個結點的父節點相同,那麼這個圖是環。
環的長度是d[a]+d[b]+1,這個很好理解吧,畫個圖就明白了。
如果a到b有邊,那麼就把a連到b上,而且d[a] = d[b]+1,這個也很好理解吧。
然後求結點到父節點的的長度就是在路徑壓縮的時候更新一下d,d[x] += d[last]。
程式碼:
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5+7; const int INF = 1e9+7; int ans = INF; int p[maxn]; int d[maxn]; void init() { for(int i=0;i<maxn;i++) { p[i] = i; } } int find(int x) { if(p[x]!=x) { int last = p[x]; p[x] = find(p[x]); d[x] += d[last]; } return p[x]; } void check(int a,int b) { int x = find(a); int y = find(b); if(x!=y) { p[x] = y; d[a] = d[b]+1; } else { ans = min(ans,d[a]+d[b]+1); } } int main() { int n; cin>>n; init(); for(int i=1;i<=n;i++) { int tmp; cin>>tmp; check(i,tmp); } cout<<ans<<endl; return 0; }