1. 程式人生 > >環套樹 or 基環樹 找環

環套樹 or 基環樹 找環

esp stdout set ++ vector 算法 open oid efi

最近學了一個蠻好的bfs找基環樹上環的算法;

不過我做起題目來 , 感覺身心收到了摧殘 , 感覺一題回到語法篇;

廢話不多說 , 介紹找環的方法 , 以 無向基環樹為例;

三步求環大法;

第一步 在加邊的時候 , 統計一下每個點的度 ;

第二步 用bfs遍歷度等於1的點(就是葉子節點 , 只有一條邊) 去掉相關的邊 , 並且更新度

第三步 從一個度不等於零的點開始進行邊遍歷;

獻上我醜陋的代碼

#include<cstdio>
#include<queue>
#include<map>
#include<cstring>
#include
<cstdlib> #include<deque> #include<iostream> #include<set> #include<vector> #include<algorithm> #define inf 0x3f3f3f3f #define ll long long #define M 1010000 using namespace std; int n , head[M] , net[M << 1] , u[M << 1] , v[M << 1] , d[M] , cnt = 1
; int q[M] , f[M] , du[M] , tot; ll g[M]; void add(int x , int y , int z){ u[++cnt] = y , d[cnt] = z , net[cnt] = head[x] , head[x] = cnt; ++du[y]; } void bfs(int x){ int y , l , r , now; l = r = 1; q[1] = x ; while (l <= r){ now = q[l] , ++l , --du[now];
for (int i = head[now] ; i ; i = net[i]){ if (du[y = u[i]] > 1){ if (--du[y] == 1) q[++r] = y; } } } } void find_hoop(int x){ int l , r , now , y; l = r = 1 , q[1] = x; f[++tot] = x ; while (l <= r){ now = q[l] , ++l; for (int i = head[now] ; i ; i = net[i]){ if (du[y = u[i]] && !v[i]){ v[i] = v[i^1] = 1; f[++tot] = y; g[tot] = g[tot - 1] + d[i]; q[++r] = y; break; // 一定要break , 不然會走兩條邊; } } } } int main(){ // freopen("A.out" , "w" , stdout); freopen("c1.in" , "r" , stdin); scanf("%d" , &n); for (int i = 1 ; i <= n ; ++i){ int a , b , c; scanf("%d%d%d" , &a , &b , &c); add(a , b , c) , add(b , a , c); } for (int i = 1 ; i <= n ; ++i){ if (du[i] == 1) bfs(i); } for (int i = 1 ; i <= n ; ++i){ if (du[i]){ find_hoop(i); for (int j = 1 ; j <= tot ; ++j){ du[f[j]] = 0; } } } for (int i = 1 ; i <= tot ; ++i){ printf ("%d " , f[i]); } printf ("\n%lld" , g[tot]); return 0; }

裏面說明一個東西 , add有向邊的時候 , 我是cnt = 1 開始的;

這樣 訪問一條邊的時候 , 設這條邊是i 那麽 i^1 , 就是他的反向邊 , 得到另一個點;

f數組記錄點 , g 記錄邊權總和 (環上的)

有向邊的做法也是類似的;

環套樹 or 基環樹 找環