zoukankan      html  css  js  c++  java
  • UVA 11733 最小生成深林

    ---恢复内容开始---

    一、题目描述:给定n(<=10000)个点,m(<=100000)条边,给出修每条边的花费f[i],可在某些点上修机场,给出修机场花费w。在一个连通分量里,只要有一个机场,则所有点都能达到机场。求最小修机场和修路的最小花费和。

    二、策略:贪心+证明

    三、具体算法和证明:

    1、因为这道题本身和构建连通分量相关,所以我先向最小生成树考虑。

    2、我们对所有的边按照花费f从小到大排序,假设这样一种情况:

    f1<=f2<=f3<=f4<=f5<=f6.........<=fi<=.........fn

    3、假设从fi开始往后f>w。对于前面的边,首先拿出第一条边f1建边,两点选一个建造机场;对于后续读取的边,如果两个顶点在同一联通分量里,显然这条边不需要修建。关键是下面两种情况:

     

     

    (1)红色是当前读取到的边,那么我们发现在7节点单独建一个新的飞机场显然更划算;我们可以用归纳证明得,当读取到后续的边,只要f>w时,在两个节点上分别建飞机场是最优的(比建一个飞机场和一条边,或者在一个联通分量中建几个机场和几条边(见右上图)都要更优)
    2)遇到一个新的联通分量,简单类推,那么和上述的建边过程相同的。

    四、算法实现:

    f小于w的部分(最小生成树算边权和count+并查集判联通分量t1);f大于w的个数t2

    答案为count+wt1+t2

    我们可以发现上面的公式,利用并查集本身特点是是可合并,所以就是P[x]==[x]判总的联通分量即可。

    五、代码实现:

     

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 int p[11000];
     5 struct edge
     6 {
     7     int u;
     8     int v;
     9     int f;
    10     edge() {}
    11     edge(int uu,int vv,int ff)
    12     {
    13         u=uu;
    14         v=vv;
    15         f=ff;
    16     }
    17 } e[111000];
    18 int find(int x)
    19 {
    20     return p[x] != x ? p[x]=find(p[x]) : x;
    21 }
    22 int cmp(edge a,edge b)
    23 {
    24     return a.f<b.f;
    25 }
    26 int main()
    27 {
    28     int t;
    29     scanf("%d",&t);
    30     for(int cas=1; cas<=t; cas++)
    31     {
    32         int n,m,w;
    33         int cnt=0;
    34         scanf("%d%d%d",&n,&m,&w);
    35         for(int i=1;i<=n;i++)
    36         p[i]=i;
    37         for(int i=1; i<=m; i++)
    38         {
    39             int u;
    40             int v;
    41             int f;
    42             scanf("%d%d%d",&u,&v,&f);
    43             e[cnt++]=edge(u,v,f);
    44         }
    45         sort(e,e+cnt,cmp);
    46         int p1=m;
    47         for(int i=0;i<m;i++)
    48         if (e[i].f>=w) {p1=i;break;}
    49         long long  tc=0;
    50         for(int i=0;i<p1;i++)//从p1开始,以后f>w
    51         {
    52             int pu=find(e[i].u);
    53             int pv=find(e[i].v);
    54 
    55             if (pu==pv) continue;
    56             tc+=e[i].f;//建边的总花费
    57             p[pu]=pv;
    58         }
    59         int co=0;
    60         for(int i=1;i<=n;i++)
    61         {
    62             if (i==p[i]) co++;//判连通分量的个数
    63         }
    64         tc+=co*w;
    65         printf("Case #%d: %lld %d
    ",cas,tc,co);
    66 
    67     }
    68     return 0;
    69 }

    ---恢复内容结束---

  • 相关阅读:
    tbody的有趣问题
    如何去掉a标签的虚框
    在ubuntu下安装ruby on rails环境
    odoo 新建模块命令
    安装sentry的几个命令,日志监控系统
    腾讯云docker加速
    odoo技术笔记
    零基础实现摄像头的全平台直播 (一)内网直播的实现
    EasyNVR、EasyDSS二次开发RTMP、HLS流在web页面进行无插件播放(demo)
    EasyDSS流媒体服务器和EasyDSS云平台异同
  • 原文地址:https://www.cnblogs.com/little-w/p/3422426.html
Copyright © 2011-2022 走看看