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 }

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

  • 相关阅读:
    姐姐的vue(1)
    LeetCode 64. Minimum Path Sum 20170515
    LeetCode 56. 56. Merge Intervals 20170508
    LeetCode 26. Remove Duplicates from Sorted Array
    LeetCode 24. Swap Nodes in Pairs 20170424
    LeetCode 19. Remove Nth Node From End of List 20170417
    LeetCode No.9 Palindrome Number 20170410
    LeetCode No.8. String to Integer (atoi) 2017/4/10(补上一周)
    LeetCode No.7 Reverse Integer 2017/3/27
    LeetCode No.4 Median of Two Sorted Arrays 20170319
  • 原文地址:https://www.cnblogs.com/little-w/p/3422426.html
Copyright © 2011-2022 走看看