zoukankan      html  css  js  c++  java
  • 牛客寒假6-I |最小生成树 + 重新建图 (+ floyd)

    题目地址:https://ac.nowcoder.com/acm/contest/3007/I

    思路

    代码

    代码1:最小生成树 + floyd

    最小生成树的时候,保存n-1条边即答案。
    floyd求点到点的最短距离,复杂度O(N^3)能过

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn= 610;
    const int maxm = 1000000;
    
    struct edge{
        int u,v,w;
        bool operator < (const edge &a) const{
            return w < a.w;
        }
    }e[maxm];
    
    struct node{
    	int v,w;
    };
    
    vector<node> g[maxn];
    
    int fa[maxn],n,m,len = 0;
    
    int get(int x){
        if(fa[x] == x){
            return fa[x];
        }
        return fa[x] = get(fa[x]);
    }
    
    int dist[maxn],dis[maxn][maxn];
    vector<int> ans;
    int a[maxn][maxn];
    
    void init(){
    	memset(dis,0x3f3f3f3f,sizeof dis);
        for(int i = 1;i <= n;i++){
            dis[i][i] = 0;
        }
    } 
    
    void floyd(){
    	for(int k=1;k<=n;k++){
    		for(int i=1;i<=n;i++){
    			for(int j=1;j<=n;j++){
    				dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);
    			}
    		}
    	}
    }
    
    int main() {
        cin>> n;
        len = 0;
        init();
        for(int i=1;i<=n;i++)
        	for(int j=1;j<=n;j++) cin>>a[i][j];
        for(int i=1;i<=n;i++){
        	for(int j=1;j<=n;j++){
        		if(i < j) e[len].u = i,e[len].v = j,e[len].w = a[i][j],len++;
    		}
    	}
        sort(e,e+len);
        for(int i=1;i<=n;i++) fa[i] = i;
        int sum = 0;
        for(int i=0;i<len;i++){
            int x = get(e[i].u), y = get(e[i].v);
            if(x != y){ //并查集求得最短边长 
                fa[x] = y;
                ans.push_back(e[i].w); //存答案 
                dis[e[i].u][e[i].v] = dis[e[i].v][e[i].u] = e[i].w; //记录新的邻接矩阵 
                sum += e[i].w;
            }
        }
        floyd(); //跑最短路 求出点到点的最短距离 500^3 
        for(int i=1;i<=n;i++){
        	for(int j=1;j<=n;j++){
        		if(a[i][j] != dis[i][j]){
        			cout<<"No"<<endl;
        			return 0;
    			}
    		}
    	}
    	cout<<"Yes"<<endl; 
    	//升序输出边长 
    	sort(ans.begin(),ans.end());
    	for(int i=0;i<ans.size();i++) cout<<ans[i]<<endl;
        return 0;
    }
    

    代码2:最小生成树 + dfs求各点到根距离 + 重新建图

    最小生成树的时候使用邻接表重新建图。
    dfs求各点到根的距离,就能判断是否合法,为什么?因为树上每个点到根的距离是唯一的,所以两点之间距离 = 点1到根 + 点2到根 也是唯一的。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn= 610;
    const int maxm = 1000000;
    
    struct edge{
        int u,v,w;
        bool operator < (const edge &a) const{
            return w < a.w;
        }
    }e[maxm];
    
    struct node{
    	int v,w;
    };
    
    vector<node> g[maxn];
    
    int fa[maxn],n,m,len = 0;
    int vis[maxn];
    
    int get(int x){
        if(fa[x] == x){
            return fa[x];
        }
        return fa[x] = get(fa[x]);
    }
    
    int dist[maxn],dis[maxn][maxn];
    vector<int> ans;
    
    void dfs(int x,int fa,int dis){
    	dist[x] = dis;
    	for(int i=0;i<g[x].size();i++){
    		int v = g[x][i].v;
    		if(v != fa){
    			int w = g[x][i].w;
    			dfs(v,x,dis+w);
    		}
    	}
    }
    
    void dfs(int x,int dis){
    	dist[x] = dis;
    	vis[x] = 1;
    	for(int i=0;i<g[x].size();i++){
    		int v = g[x][i].v;
    		if(!vis[v]){
    			int w = g[x][i].w;
    			dfs(v,dis+w);
    		}
    	}
    }
    
    int main() {
        cin>> n;
        len = 0;
        for(int i=1;i<=n;i++){
        	for(int j=1;j<=n;j++){
        		int w;
        		cin>>w;
        		if(i < j)
        			e[len].u = i,e[len].v = j,e[len].w = w,len++;
        		dis[i][j] = w;
    		}
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=n;j++){
    			if(dis[i][j] != dis[j][i]){
    				puts("No");
    				return 0;
    			}
    		}
    	}
        sort(e,e+len);
        for(int i=1;i<=n;i++){
            fa[i] = i;
        }
        int sum = 0;
        for(int i=0;i<len;i++){
            int x = get(e[i].u), y = get(e[i].v);
            if(x != y){
                fa[x] = y;
                ans.push_back(e[i].w); //存储最小生成树的n-1条最短边 
    			g[e[i].u].push_back({e[i].v,e[i].w}); //存储新图的邻接表 
    			g[e[i].v].push_back({e[i].u,e[i].w}); //存储新图的邻接表 
                sum += e[i].w;
            }
        }
        //找起点(根)
        int s = 1;
    	for(int i=1;i<=n;i++){
    		if(g[i].size() == 1){
    			s = i;
    			break;
    		}
    	} 
    	//dfs统计距离 两个版本dfs都可 
    	dfs(s,-1,0);  
    //	dfs(s,0);
    	//与输入的最短距离作比较 
    	for(int i=1;i<=n;i++){
    		if(dist[i] != dis[s][i]){
    			cout<<"No"<<endl;
    			return 0;
    		}
    	}
    	cout<<"Yes"<<endl; 
    	//升序输出边长 
    	sort(ans.begin(),ans.end());
    	for(int i=0;i<ans.size();i++) cout<<ans[i]<<endl;
        return 0;
    }
    
  • 相关阅读:
    python之打开python源文件方法
    python学习网站
    python知识点
    计算机概念--鸭子类型
    装饰器、函数调用 语句分析法
    python相关软件安装
    python之字典的作用
    [转载]理解HTML语义化
    Java 入门 代码2浮点数据类型
    Java入门1dayCode
  • 原文地址:https://www.cnblogs.com/fisherss/p/12330410.html
Copyright © 2011-2022 走看看