zoukankan      html  css  js  c++  java
  • HDU 4081 Qin Shi Huang's National Road System(最小生成树/次小生成树)

    题目链接:传送门

    题意:

    有n坐城市,知道每坐城市的坐标和人口。如今要在全部城市之间修路,保证每一个城市都能相连,而且保证A/B 最大。全部路径的花费和最小,A是某条路i两端城市人口的和,B表示除路i以外全部路的花费的和(路径i的花费为0).

    分析:

    先求一棵最小生成树,然后枚举每一条最小生成树上的边,删掉后变成两个生成树。然后找两个集合中点权最大的两

    个连接起来。这两个点中必定有权值最大的那个点。所以直接从权值最大的点開始dfs。

      为了使A/B的值最大,则A尽可能大,B尽可能小。所以B中的边一定是MST上去掉一条边后的剩余全部边。首先用O(N^2)算出

      MST,然后依次枚举。删去MST上的每一条边。MST变成两棵树T1和T2,然后在剩余的边(即不在MST上的边),以及这条删

      去的边中找到该边的两点的权值和最大以及可以连接T1和T2的边。A=删去边后的替换边的两点的权值和,B=删去该边后的MST

      的值。求A/B最大。

    则A尽可能大,A各自是T1和T2中最大的两个点,则全部点中权值最大的点一定在A中。由此在MST上从权值

      最大的点作为root。開始dfs。递归求出子树中的每一个最大的点以及求出A/B的比值,求出最大。

    分析转载自:传送门

    我的理解。首先非常明显我们是须要求出最小生成树的,然后我们能够枚举边(u,v)中的边,非常明显枚举的边都会

    与原来MST中的边形成一个环,由于这个边不在MST中,那么这个边的权值一定是大于MST中连接U,V的边的,因此

    我们在这个环里去掉的应该是权值最大的边。

    代码例如以下:

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    using namespace std;
    
    const int maxn = 1e3+10;
    
    const int inf = 1e9+10;
    
    struct point{
        int x,y;
    }a[maxn];
    
    int head[maxn],par[maxn],peo[maxn];
    
    bool vis[maxn];
    
    int ip,mmax;
    double ans ,mst;
    
    struct tree{
        int u,v;
        double w;
        tree(){}
        tree(int _u,int _v,double _w):u(_u),v(_v),w(_w){}
        bool operator < (const struct tree &tmp)const{
            return w<tmp.w;
        }
    }mp[maxn*maxn];
    
    struct nod{
        int to,next;
        double w;
    }edge[maxn*2];
    
    double calu(point a,point b){
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    
    void add(int u,int v,double w){
        edge[ip].to=v;
        edge[ip].w=w;
        edge[ip].next=head[u];
        head[u]=ip++;
    }
    
    int find_par(int x){
        if(x!=par[x]) return par[x]=find_par(par[x]);
        return par[x];
    }
    
    bool Union(int x,int y){
        x=find_par(x);
        y=find_par(y);
        if(x!=y){
            par[x]=y;
            return true;
        }
        return false;
    }
    
    void init(){
        for(int i=0;i<maxn;i++) par[i]=i;
        ip=mmax=0;
        ans=mst=0;
        memset(head,-1,sizeof(head));
        memset(vis,0,sizeof(vis));
    }
    
    int dfs(int root){
        vis[root]=1;
        int peo_max=peo[root];
        for(int i=head[root];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(!vis[v]){
                int tmp = dfs(v);
                peo_max=max(peo_max,tmp);
                ans=max(ans,(tmp+mmax)/(mst-edge[i].w));
            }
        }
        return peo_max;
    }
    
    int main(){
        int t,n,root;
        scanf("%d",&t);
        while(t--){
            init();
            scanf("%d",&n);
            for(int i=0;i<n;i++){
                scanf("%d%d%d",&a[i].x,&a[i].y,&peo[i]);
                if(peo[i]>mmax){
                    mmax=peo[i];
                    root=i;
                }
            }
            int cnt = 0;
            for(int i=0;i<n;i++){
                for(int j=i+1;j<n;j++){
                    mp[cnt++]=tree(i,j,calu(a[i],a[j]));
                }
            }
            sort(mp,mp+cnt);
            for(int i=0;i<cnt;i++){
                if(Union(mp[i].u,mp[i].v)){
                    mst+=mp[i].w;
                    add(mp[i].u,mp[i].v,mp[i].w);
                    add(mp[i].v,mp[i].u,mp[i].w);
                }
            }
            dfs(root);
            printf("%.2lf
    ",ans);
        }
        return 0;
    }



     


     


     

  • 相关阅读:
    安卓系统
    移动互联网产品设计的原则
    Java 笔记10
    Get Android Source Code
    Spinner Animation
    Java 笔记09
    Java 笔记07
    Java 笔记08
    例题
    例题
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5399124.html
Copyright © 2011-2022 走看看