洛谷 P 4180 次小生成树
生活随笔
收集整理的這篇文章主要介紹了
洛谷 P 4180 次小生成树
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目描述
小C最近學了很多最小生成樹的算法,Prim算法、Kurskal算法、消圈算法等等。正當小C洋洋得意之時,小P又來潑小C冷水了。小P說,讓小C求出一個無向圖的次小生成樹,而且這個次小生成樹還得是嚴格次小的,也就是說:如果最小生成樹選擇的邊集是EM,嚴格次小生成樹選擇的邊集是ES,那么需要滿足:(value(e)表示邊e的權值)?\sum_{e \in E_M}value(e)<\sum_{e \in E_S}value(e)∑e∈EM??value(e)<∑e∈ES??value(e)
這下小 C 蒙了,他找到了你,希望你幫他解決這個問題。
輸入格式
第一行包含兩個整數N 和M,表示無向圖的點數與邊數。 接下來 M行,每行 3個數x y z 表示,點 x 和點y之間有一條邊,邊的權值為z。
輸出格式
包含一行,僅一個數,表示嚴格次小生成樹的邊權和。(數據保證必定存在嚴格次小生成樹)
輸入輸出樣例
輸入 #1復制
5 6 1 2 1 1 3 2 2 4 3 3 5 4 3 4 3 4 5 6輸出 #1復制
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<algorithm> #include<vector> #include<cstdio> typedef long long ll; using namespace std; const int M=1e5+100; ll n,m,res,ans=0x3f3f3f3f,mx; int f[M],fa[25][M],dep[M]; ll d[2][25][M]; bool used[3*M],vis[M]; vector<int> a[M]; struct Edge {int from, to;ll val;bool operator < (const Edge y){return val < y.val;} } e[3*M]; int F(int x) {if(f[x]==x)return x;return f[x]=F(f[x]); } void kruskal() //kruskal 算最大生成樹(已保證任意兩點之間最小限重最優) {sort(e,e+m);int lef=n-1;for(int i=1; i<=n; ++i)f[i]=i;for(int i=0; i<m && lef; ++i){int x=F(e[i].from),y=F(e[i].to);if(x!=y){f[x]=y;res+=e[i].val;used[i]=1;--lef;mx=max(mx, e[i].val);}} } void dfs(int x) //深搜建樹(可能不止一棵,因為數據未保證是連通圖) {vis[x]=true;for(int i=1; i<=23; ++i){fa[i][x]=fa[i-1][fa[i-1][x]];ll t1=d[0][i-1][x], t2=d[0][i-1][fa[i-1][x]];d[0][i][x]=max(t1, t2);d[1][i][x]=max(d[1][i-1][x], d[1][i-1][fa[i-1][x]]);if(t1!=t2)d[1][i][x]=max(d[1][i][x], min(t1, t2));}for(int i=0; i<a[x].size(); ++i){int t=e[a[x][i]].to+e[a[x][i]].from-x;if(vis[t])continue; //vis為1表示是父節點dep[t]=dep[x]+1;fa[0][t]=x;d[0][0][t]=e[a[x][i]].val;dfs(t);} } int lca(int u,int v) {if(dep[u]<dep[v])swap(u,v);if(dep[u]!=dep[v]) //將深度做相等{for(int i=23,h=dep[u]-dep[v]; i>=0; --i)if(h&(1<<i))u=fa[i][u];}if(u==v)return u; //如果已經在一個節點上就直接返回for(int i=23; i>=0; --i)if(fa[i][u]!=fa[i][v])u=fa[i][u], v=fa[i][v];return fa[0][u]; } ll get(int u,int v,int c) {int fht=lca(u,v);ll m1=0,m2=0;for(int i=23,h1=dep[u]-dep[fht],h2=dep[v]-dep[fht]; i>=0; --i){if(h1&(1<<i)){if(d[0][i][u]>m1)m2=m1,m1=d[0][i][u];else if(d[0][i][u]>m2)m2=d[0][i][u];elsem2=max(m2, d[1][i][u]);}if(h2&(1<<i)){if(d[0][i][v]>m1)m2=m1,m1=d[0][i][v];else if(d[0][i][v]>m2)m2=d[0][i][v];elsem2=max(m2, d[1][i][v]);}}if(m1==c)return c-m2;elsereturn c-m1; } int main() {scanf("%d%d",&n,&m);for(int i=0; i<m; ++i){int u,v;ll w;scanf("%d%d%lld",&u,&v,&w);e[i].from=u;e[i].to=v;e[i].val=w;}kruskal();for(int i=0; i<m; ++i)if(used[i]){a[e[i].from].push_back(i);a[e[i].to].push_back(i);}dep[1]=1;dfs(1);for(int i=0; i<m; ++i)if(!used[i]){if(e[i].val-mx>ans)break;ll t=get(e[i].from, e[i].to, e[i].val);ans=min(ans, t);}return printf("%lld\n",res+ans),0; }?
總結
以上是生活随笔為你收集整理的洛谷 P 4180 次小生成树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VMware ESXi 6.7基础操作
- 下一篇: 曼哈顿距离和欧拉距离