1. 程式人生 > >嚴格次小生成樹 並查集和數的綜合應用

嚴格次小生成樹 並查集和數的綜合應用

【問題描述】

  小C最近學了很多最小生成樹的演算法,Prim演算法、Kurskal演算法、消圈演算法等等。

  正當小C洋洋得意之時,小P又來潑小C冷水了。小P說,讓小C求出一個無向圖的次小生成樹,而且這個次小生成樹還得是嚴格次小的,也就是說:如果最小生成樹選擇的邊集是EM,嚴格次小生成樹選擇的邊集是ES,那麼需要滿足:(value(e)表示邊e的權值)
         
  這下小C蒙了,他找到了你,希望你幫他解決這個問題。

【輸入格式】

  第一行包含兩個整數N 和M,表示無向圖的點數與邊數。 接下來 M行,每行 3個數x y z 表示,點x和點y之間有一條邊,邊的權值為z。

【輸出格式】

  包含一行,僅一個數,表示嚴格次小生成樹的邊權和。(資料保證必定存在嚴格次小生成樹)

【輸入樣例】

5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6

【輸出樣例】

11

【資料範圍】

資料中無向圖無自環;
50% 的資料N≤2 000 M≤3 000;
80% 的資料N≤50 000 M≤100 000;
100% 的資料N≤100 000 M≤300 000 ,邊權值非負且不超過 10^9 。

這道題就是生成一個嚴格次小生成樹,先生成最優生成樹(詳見最優生成樹
),再在樹上進行加邊和刪邊處理,生成嚴格次小生成樹。

#include<iostream>
#include<cstdio> #include<cstdlib> #include<vector> #include<algorithm> #include<cstring> #include<cmath> using namespace std; const int maxn=100005; struct shu { int u,v,w; }; vector<shu>g; vector<int>a[maxn],s[maxn]; int n,m,fa[maxn],pa[maxn],deep[maxn]={0
},dist[maxn]={0}; bool usd[300005]={0}; bool my(shu a,shu b) { return a.w<b.w; } void in() { for(int i=0;i<=n;i++) pa[i]=i; } void init() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); g.push_back((shu){x,y,z}); } in(); sort(g.begin(),g.end(),my); } int find(int x) { if(pa[x]==x) return x; pa[x]=find(pa[x]); return pa[x]; } bool judge(int x,int y) { return find(x)==find(y); } void Union(int x,int y) { pa[find(x)]=find(y); } long long kruscr() { long long sum=0; for(int i=0;i<g.size();i++) { if(judge(g[i].u,g[i].v)) continue; Union(g[i].u,g[i].v); a[g[i].u].push_back(g[i].v);//生成最小生成樹。 a[g[i].v].push_back(g[i].u); s[g[i].v].push_back(g[i].w); s[g[i].u].push_back(g[i].w); usd[i]=1; sum+=(long long)g[i].w; } return sum; } void dfs(int x,int y,int z) { fa[x]=y; deep[x]=z; for(int i=0;i<a[x].size();i++) { int j=a[x][i]; if(j==y) continue; dist[j]=dist[x]+s[x][i]; dfs(j,x,z+1); } } int getmax(int x,int y,int z)//查詢路徑上比新邊小的最大邊。 { int maxv=0; if(deep[x]<deep[y]) swap(x,y); while(deep[x]>deep[y]) { if(dist[x]-dist[fa[x]]<z) maxv=max(maxv,dist[x]-dist[fa[x]]); x=fa[x]; } while(x!=y) { if(dist[x]-dist[fa[x]]<z) maxv=max(maxv,dist[x]-dist[fa[x]]); if(dist[y]-dist[fa[y]]<z) maxv=max(maxv,dist[y]-dist[fa[y]]); x=fa[x]; y=fa[y]; } return maxv; } int main() { //freopen("in.txt","r",stdin); init(); long long sum=kruscr(); dfs(1,1,1); long long ans=100000000000000ll; for(int i=0;i<g.size();i++) if(!usd[i]) { int x=g[i].u,y=g[i].v,z=g[i].w; int t=getmax(x,y,z); ans=min(ans,sum+z-t); } cout<<ans; return 0; }