zoukankan      html  css  js  c++  java
  • LOJ题解#136. 最小瓶颈路 DFS+Kruskal

    • 题目链接:

      https://loj.ac/problem/136

    • 思路:

      在我的这篇博客中已经讲到什么是最短瓶颈路,同时给出了一个用Kruskal求最短瓶颈路的一个简洁易懂的方法,然而这道题目可以看作求所有点对的最短瓶颈路,显然那篇博客题解的方法不太管用,于是改进后有了这个算法:

      我们还是先用Kruskal求出最小生成树,同时记录最小生成树中个点与哪些点相连.然后我们把这个最小生成树转化为有根树来进行DFS处理。若正在处理的点编号为(u),它的一个后继点(即将DFS)编号(v),已经DFS过的一个点编号(x),(ans[i][j])表示(i)(j)的最短瓶颈路的大小。根据定义,显然:

      (ans[x][v]=ans[v][x]=max(ans[u][v],ans[x][u],w(u,v)))

      可以看到正在DFS的节点相当于一个转承的作用

      时间复杂度(O(mlog m+n+k))

    • 代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cctype>
    #include <cmath>
    #include <vector>
    #include <map>
    #include <queue>
    #define ll long long 
    #define ri register int 
    using namespace std;
    const int maxn=1005;
    const int maxm=100005;
    const int inf=0x7fffffff;
    template <class T>inline void read(T &x){
    	x=0;int ne=0;char c;
    	while(!isdigit(c=getchar()))ne=c=='-';
    	x=c-48;
    	while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
    	x=ne?-x:x;
    	return ;
    }
    struct Edge{
    	int u,v,w;
    	Edge(int x,int y,int z){u=x,v=y,w=z;}
    	Edge(){u=v=0,w=inf;}
    	bool operator <(const Edge &b)const{
    		return w<b.w;
    	}
    }edge[maxm];
    int n,m,k;
    vector <Edge>g[maxn];
    int fa[maxn];
    int get(int x){
    	if(fa[x]!=x)fa[x]=get(fa[x]);
    	return fa[x];
    }
    void Kruskal(){
    	int cnt=0,u,v,w;
    	for(ri i=1;i<=n;i++)fa[i]=i;
    	for(ri i=1;i<=m;i++){
    		u=edge[i].u,v=edge[i].v,w=edge[i].w;
    		u=get(u),v=get(v);
    		if(u!=v){
    			fa[u]=v;
    			g[u].push_back(Edge(u,v,w));
    			g[v].push_back(Edge(v,u,w));
    			cnt++;
    			if(cnt==n-1)break;
    		}
    	}
    	return ;
    }
    bool vis[maxn];
    int ans[maxn][maxn];
    void dfs(int now){
    	int u,v,w;
    	vis[now]=1;
    	for(ri i=0;i<g[now].size();i++){
    		v=g[now][i].v,w=g[now][i].w;
    		if(!vis[v]){
    			for(ri j=1;j<=n;j++){
    				if(vis[j])//如果它在有根树中已被访问过 
    				{
    					ans[j][v]=ans[v][j]=max(ans[now][v],max(ans[now][j],w));
    				}
    			}
    			dfs(v);
    		}	
    	}
    	return ;
    }
    int main(){
    	int u,v,w;
    	read(n),read(m),read(k);
    	for(ri i=1;i<=m;i++){
    		read(u),read(v),read(w);
            edge[i].u=u,edge[i].v=v,edge[i].w=w;
    	}
    	sort(edge+1,edge+1+m);
    	Kruskal();
    	memset(ans,0,sizeof(ans));
    	memset(vis,0,sizeof(vis));
    	dfs(1);
    	while(k--){
    		read(u),read(v);
    		if(!ans[u][v])puts("-1");
    		else printf("%d
    ",ans[u][v]);
    	}
    	return 0;
    }
    
    • 注:

      1. 这个算法来自这里,但是他的代码中有一个错误就是上文提到(ans[i][j])的转移

      2. 有兴趣的可以看一下增强版:https://loj.ac/problem/137

  • 相关阅读:
    2018个人面试记录
    如何用纯代码实现图片CSS3
    JS数组删除
    JS数组去重
    HTML--使用提交按钮,提交数据
    HTML--使用下拉列表框进行多选
    HTML--使用下拉列表框,节省空间
    HTML--使用单选框、复选框,让用户选择
    HTML--文本域,支持多行文本输入
    HTML--文本输入框、密码输入框
  • 原文地址:https://www.cnblogs.com/Rye-Catcher/p/9194967.html
Copyright © 2011-2022 走看看