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;
    }
    
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法提高 贪吃的大嘴
    Java实现 蓝桥杯VIP 算法提高 贪吃的大嘴
    Java实现 蓝桥杯VIP 算法提高 贪吃的大嘴
    Java实现 蓝桥杯VIP 算法提高 贪吃的大嘴
    Java实现 蓝桥杯VIP 算法提高 士兵排队问题
    Java实现 蓝桥杯VIP 算法提高 士兵排队问题
    Java实现 蓝桥杯VIP 算法提高 士兵排队问题
    Java实现 蓝桥杯VIP 算法提高 士兵排队问题
    Java实现 蓝桥杯VIP 算法提高 数字黑洞
    Minifilter微过滤框架:框架介绍以及驱动层和应用层的通讯
  • 原文地址:https://www.cnblogs.com/fisherss/p/12330410.html
Copyright © 2011-2022 走看看