图论 —— 生成树 —— 最小瓶颈路
生活随笔
收集整理的這篇文章主要介紹了
图论 —— 生成树 —— 最小瓶颈路
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
【概述】
最小瓶頸路是指:在一張無向圖上,對于點 u、v 找出從 u、v 的一條簡單路徑,使得路徑上行所有邊中最大值最小。
根據(jù)查詢次數(shù)不同,最小瓶頸路問題可分為單次查詢和多次查詢。
【單次查詢】
由于要求最大值最小,答案肯定處于所有邊中最小值和最大值之間,那么進(jìn)行二分在 check 的時候以二分值為基準(zhǔn)進(jìn)行 DFS,不經(jīng)過權(quán)值大于二分值的邊,如果能搜到終點,則說明二分值過大,如果不能搜到終點,則說明二分值過小。
struct Edge {int to;int dis; } edge[N]; int head[N],next[N]; int vis[N]; int n,m,start,endd; int tot,mid; void add_edge(int u,int v,int w) {//添邊tot++;edge[tot].to=v;edge[tot].dis=w;next[tot]=head[u];head[u]=tot; } bool dfs(int x) {//dfs搜索if(x==endd)return true;bool flag=false;vis[x]=1;for(int i=head[x]; i!=-1; i=next[i]) {int y=edge[i].to;int w=edge[i].dis;if(vis[y]||w>mid) {continue;}flag=flag|dfs(y);}return flag; } int main() {cin>>n>>m;//n個點m條邊cin>>start>>endd;//從start到enddint left=INF,right=-INF;memset(head,-1,sizeof(head));for(int i=1; i<=m; i++) {int u,v,w;scanf("%d%d%d",&u,&v,&w);left=min(left,w);right=max(right,w);add_edge(u,v,w);add_edge(v,u,w);}int ans;while(left<=right) {//二分答案mid=(left+right)>>1;memset(vis,0,sizeof(vis));if(dfs(start)) {ans=mid;right=mid-1;}else {left=mid+1;}}cout<<ans<<endl;return 0; }【多次查詢】
由于最小瓶頸路可能有多條,那么無向圖最小生成樹中 u 到 v 的路徑一定是 u 到 v 的最小瓶頸路之一。
首先對無向圖求最小生成樹 MST,然后對于每個詢問 (u,v),利用倍增來回答 u 到 v 的路徑上的權(quán)值最大值。
struct Edge {int to;int dis; }edge[N]; int head[N],next[N]; int father[N],dep[N]; int G[1000][1000],maxx[1000][1000]; int n,m,q,root; int tot,num; void addEdge(int u,int v,int w) {tot++;edge[tot].to=v;edge[tot].dis=w;next[tot]=head[u];head[u]=tot; } int Find(int x) {return father[x]<0?x:father[x]=Find(father[x]); } void Union(int u,int v,int w) {int x=Find(u),y=Find(v);if(x==y)return;if(-father[x]>-father[y]) {father[x]+=father[y];father[y]=x;}else {father[y]+=father[x];father[x]=y;}addEdge(u,v,w);addEdge(v,u,w);num++; } void dfs(int x) {for(int i=head[x]; i!=-1; i=next[i]) {int y=edge[i].to;int w=edge[i].dis;if(y==G[x][0])continue;G[y][0]=x;maxx[y][0]=w;dep[y]=dep[x]+1;dfs(y);} } void init() {//對G進(jìn)行初始化for(int j=1; (1<<j)<=n; j++) {for(int i=1; i<=n; i++) {if(G[i][j-1]) {G[i][j]=G[G[i][j-1]][j-1];maxx[i][j]=max(maxx[i][j-1],maxx[G[i][j-1]][j-1]);}}} } int query(int x,int y) {//查詢從x到y(tǒng)的最小瓶頸路if(dep[x]<dep[y])swap(x,y);int temp=-INF;int t=(int)(log(dep[x])/log(2));for(int j=t; j>=0; j--) {if(dep[x]-(1<<j)>=dep[y]) {temp=max(temp,maxx[x][j]);x=G[x][j];}}if(x==y)return temp;for(int j=t; j>=0; j--) {if(G[x][j]&&G[x][j]!=G[y][j]) {temp=max(temp,max(maxx[x][j],maxx[y][j]));x=G[x][j];y=G[y][j];}}return max(temp,max(maxx[x][0],maxx[y][0])); } struct E{int u,v;int w;bool operator <(const E &rhs)const{//按邊權(quán)排序return w<rhs.w;} }e[N]; int main() {cin>>n>>m>>q;//n個點m條邊q次查詢for(int i=1; i<=m; i++)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);sort(e+1,e+m+1);//按邊權(quán)排序memset(head,-1,sizeof(head));memset(father,-1,sizeof(father));for(int i=1; i<=m; i++) {//Kruskal求最小生成樹int u=e[i].u;int v=e[i].v;int w=e[i].w;Union(u,v,w);if(num>=n-1)break;}root=(1+n)>>1;dfs(root);//從根節(jié)點開始搜索init();for(int i=1; i<=q; i++) {int u,v;scanf("%d%d",&u,&v);printf("%d\n",query(u,v));}return 0; }?
總結(jié)
以上是生活随笔為你收集整理的图论 —— 生成树 —— 最小瓶颈路的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Passing the Message(
- 下一篇: 训练日志 2019.3.10