zoukankan      html  css  js  c++  java
  • POJ 2421 Constructing Roads (最小生成树)

    题意:给出邻接矩阵,在给出q条已经建好的路,让你再建一些路,使得连通所有的村庄并且兴建的路的长度时最小的。

    思路:1.可以先将建好的路的端点合并,这里要注意的是,首先先要判断两个端点u、v的根节点是否相同,不同的话在合并。是为了防止有重复或者有环出现。

             2.可以将建好的路的cost设为0,再直接用kruskal算法。由于建边的时候是用了上三角矩阵,所以很容易用端点u、v来推出相应边的编号。

    代码1:

    #include <iostream>
    #include <algorithm>
    #include <string.h>
    #include <stdio.h>
    #include <string>
    
    using namespace std;
    
    int n,q,cost,index,a,b;
    int ans;
    
    struct Edge{
        int u,v;
        int cost;
    
        bool operator < (const Edge& tmp) const
        {
            return cost< tmp.cost;
        }
    
    }edge[5500];
    
    struct UF{
        int father[110];
    
        void unit(){
            for(int i=1;i<=n;i++){
                father[i]=i;
            }
        }
    
        int find_root(int x){
            if(father[x]!=x)
                father[x]=find_root(father[x]);
            return father[x];
        }
    
        void Union(int fa,int fb){
            father[fb]=fa;
        }
    }uf;
    
    int main()
    {
        while(scanf("%d",&n)!=EOF){
            index=0;
            for(int i=1;i<=n;i++){
                for(int j=1;j<=i;j++)
                    scanf("%d",&cost);
                for(int j=i+1;j<=n;j++){
                    scanf("%d",&cost);
                    edge[index].u=i;
                    edge[index].v=j;
                    edge[index].cost=cost;
                    index++;
                }
            }
            sort(edge,edge+index);
    
            scanf("%d",&q);
    
            uf.unit();
            int num=0;
            for(int i=1;i<=q;i++){
                scanf("%d%d",&a,&b);
                    int fa=uf.find_root(a);
                    int fb=uf.find_root(b);
                    //已经建好的,判断根节点是否一样,因为可能有重复,如果一样说明之前已经合并过,不一样的再合并
                    //也有可能已经建好的路中会有形成环的,所以也要判断一下
                    if(fa!=fb){
                        uf.Union(fa,fb);
                        num++;
                    }
            }
    
            int count=num; //统计边数
            ans=0;
            for(int i=0;i<index;i++){
                int u=edge[i].u;
                int v=edge[i].v;
                int fu=uf.find_root(u);
                int fv=uf.find_root(v);
    
                if(count>=n-1){
                    break;
                }
    
                if(fu!=fv){
                    ans+=edge[i].cost;
                    count++;
                    uf.Union(fu,fv);
    
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }

    代码2:

    #include <iostream>
    #include <algorithm>
    #include <string.h>
    #include <stdio.h>
    #include <string>
    
    using namespace std;
    
    int n,q,cost,index,a,b;
    int ans;
    int road[110][110];//road[a][b]=1表示a与b之间已经有路,防止已经建好的路中有重复
    
    struct Edge{
        int u,v;
        int cost;
    
        bool operator < (const Edge& tmp) const
        {
            return cost< tmp.cost;
        }
    
    }edge[5500];
    
    struct UF{
        int father[110];
    
        void unit(){
            for(int i=1;i<=n;i++){
                father[i]=i;
            }
        }
    
        int find_root(int x){
            if(father[x]!=x)
                father[x]=find_root(father[x]);
            return father[x];
        }
    
        void Union(int fa,int fb){
            father[fb]=fa;
        }
    }uf;
    
    int main()
    {
        while(scanf("%d",&n)!=EOF){
            index=0;
            memset(road,0,sizeof(road));
            for(int i=1;i<=n;i++){
                for(int j=1;j<=i;j++)
                    scanf("%d",&cost);
                for(int j=i+1;j<=n;j++){
                    scanf("%d",&cost);
                    edge[index].u=i;
                    edge[index].v=j;
                    edge[index].cost=cost;
                    index++;
                }
            }
            scanf("%d",&q);
            uf.unit();
            //int num=0;
            for(int i=1;i<=q;i++){
                scanf("%d%d",&a,&b);
                //防止有重复
                if(road[a][b]==0){
                    road[a][b]=1;
                    road[b][a]=1;
                    //额,忘记edge数组的下标是从0开始的,所以idx还要最后-1。。。
                    //求出相应边的编号idx
                    int idx=(2*n-a)*(a-1)/2+b-a-1;
                    edge[idx].cost=0;
                }
            }
    
            sort(edge,edge+index);
            int count=0; //统计边数
            ans=0;
            for(int i=0;i<index;i++){
                int u=edge[i].u;
                int v=edge[i].v;
                int fu=uf.find_root(u);
                int fv=uf.find_root(v);
                if(count>=n-1){
                    break;
                }
    
                if(fu!=fv){
                    ans+=edge[i].cost;
                    count++;
                    uf.Union(fu,fv);
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    DataGrip中执行ORACL语句块进行代码测试
    ORACLE存储过程中使用SELECT INOT语句避免NO_DATA_FOUND的方法
    Pandas和numpy如何显示全部数据
    qrcodejs2+html2canvas生产二维码海报vue
    SQL多表查询
    行者app定位不准的问题分析
    Gdb printer打印STL
    Linux中的文件和目录结构详解
    Linux 文件的路径以及管理
    linux创建ftp服务
  • 原文地址:https://www.cnblogs.com/chenxiwenruo/p/3373333.html
Copyright © 2011-2022 走看看