日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

图论——最小环

發布時間:2024/1/8 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 图论——最小环 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

圖論——最小環

對于一個有向圖或一個無向圖,如何求它的最小環的大小呢,默認邊的權都是1。

Floyd算法求最小環(性能差)

設節點 i i i j j j為遍歷節點 k k k為中點,那么當 i = j i=j i=j的時候,如果存在 i → k i \to k ik k → j k \to j kj,那么就會存在環 i → k → j ( i ) i \to k \to j(i) ikj(i)此時最短路就是環的大小。

#include <bits/stdc++.h>using namespace std;#define FR freopen("in.txt","r",stdin)#define UNC 1000typedef long long ll; int d[100][100]; int n,m;int flody() {int ans = UNC;for(int k = 1; k<=n; k++)for(int i = 1; i<=n; i++)for(int j = 1; j<=n; j++){d[i][j] = min(d[i][j],d[i][k] + d[k][j]);if(i == j)ans = min(ans,d[i][k] + d[k][j]);}return ans; }int main() {cin >> n >> m;for(int i = 1; i<=n; i++)for(int j = 1; j<=n; j++)d[i][j] = UNC;for(int i = 0; i<m; i++){int u,v;cin >> u >> v;d[u][v] = 1;}cout << flody();return 0; }

網上還流傳一種做法是在 k k k循環內做兩個內層循環,具體原理應該是把一個環中的節點按照從小到大排序,最小的那個就是 i i i,第二大的那就是 j j j,最大的就是 k k k,因此循環的時候 i < j < k i \lt j \lt k i<j<k,避免了重復計算,但是我不知道為什么要套兩個循環,像我上面這樣不行嗎?

注意有向圖請注意自環

拓撲排序(不通過)

注意:從入度為0的節點開始消除,剩下的都是環,這句話沒錯,但是留下的圖一定有環,只能說明存在環,不能計算最小環的大小。

Tarjan算法(通過)

在DFS過程中,如果遇到了后向邊,那么就說明遇到了環,利用時間戳計算環的大小,最小大小就是最小環的大小。

P2661

#include <bits/stdc++.h>using namespace std;#define FR freopen("in.txt","r",stdin) #define FW freopen("out1.txt","w",stdout)typedef long long ll;struct Edge {int to;int nxt; } e[200005]; int head[200005]; int d[200005]; bool vis[200005]; int ti = 0; int tot = 0; int n;inline void add(int u,int v) {tot++;e[tot].to = v;e[tot].nxt = head[u];head[u] = tot; }int ans = INT_MAX;void dfs(int curr) {ti++;d[curr] = ti;for(int ne = head[curr]; ne != 0; ne = e[ne].nxt){int v = e[ne].to;if(d[v] != 0){if(!vis[v])ans = min(ans,d[curr] - d[v] + 1);}else{dfs(v);}}vis[curr] = true; }int main() {cin >> n;for(int i = 1; i<=n; i++){int v;cin >> v;add(i,v);}for(int i = 1; i<=n; i++){if(!vis[i]) dfs(i);}cout << ans;return 0; }

并查集(通過)

代碼取自anyway。只針對于本題,本題沒有環套環,因此b一定是根節點。

#include<cstdio> #include<iostream> using namespace std; int f[200002],d[200002],n,minn,last; //f保存祖先節點,d保存到其祖先節點的路徑長。 int fa(int x) {if (f[x]!=x) //查找時沿途更新祖先節點和路徑長。 {int last=f[x]; //記錄父節點(會在遞歸中被更新)。 f[x]=fa(f[x]); //更新祖先節點。 d[x]+=d[last]; //更新路徑長(原來連在父節點上)。 }return f[x]; } void check(int a,int b) {int x=fa(a),y=fa(b); //查找祖先節點。 if (x!=y) {f[x]=y; d[a]=d[b]+1;} //若不相連,則連接兩點,更新父節點和路徑長。 else minn=min(minn,d[a]+d[b]+1); //若已連接,則更新最小環長度。 return; } int main() {int i,t;scanf("%d",&n);for (i=1;i<=n;i++) f[i]=i; //祖先節點初始化為自己,路徑長為0。 minn=0x7777777;for (i=1;i<=n;i++){scanf("%d",&t);check(i,t); //檢查當前兩點是否已有邊相連接。 }printf("%d",minn);return 0; }

總結

以上是生活随笔為你收集整理的图论——最小环的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。