zoukankan      html  css  js  c++  java
  • BZOJ 1083: [SCOI2005]繁忙的都市【Kruscal最小生成树裸题】

    1083: [SCOI2005]繁忙的都市

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 2925  Solved: 1927
    [Submit][Status][Discuss]

    Description

      城市C是一个非常繁忙的大都市,城市中的道路十分的拥挤,于是市长决定对其中的道路进行改造。城市C的道
    路是这样分布的:城市中有n个交叉路口,有些交叉路口之间有道路相连,两个交叉路口之间最多有一条道路相连
    接。这些道路是双向的,且把所有的交叉路口直接或间接的连接起来了。每条道路都有一个分值,分值越小表示这
    个道路越繁忙,越需要进行改造。但是市政府的资金有限,市长希望进行改造的道路越少越好,于是他提出下面的
    要求: 1. 改造的那些道路能够把所有的交叉路口直接或间接的连通起来。 2. 在满足要求1的情况下,改造的
    道路尽量少。 3. 在满足要求1、2的情况下,改造的那些道路中分值最大的道路分值尽量小。任务:作为市规划
    局的你,应当作出最佳的决策,选择那些道路应当被修建。

    Input

      第一行有两个整数n,m表示城市有n个交叉路口,m条道路。接下来m行是对每条道路的描述,u, v, c表示交叉
    路口u和v之间有道路相连,分值为c。(1≤n≤300,1≤c≤10000)

    Output

      两个整数s, max,表示你选出了几条道路,分值最大的那条道路的分值是多少。

    Sample Input

    4 5
    1 2 3
    1 4 5
    2 4 7
    2 3 6
    3 4 8

    Sample Output

    3 6

    HINT

    Source

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1083

    题意
    给定一张图,求其最小生成树中权值最大的边


    要是学习过最小生成树的相关概念,就会发现这道题就是直接考察的最小生成树,只不过题目没有问你最小生成树的边权和,而是让你输出最小生成树有几条边(点数-1)和权值最大的那条边的权值。


    那么什么是生成树呢?

    In the mathematical field of graph theory, a spanning tree T of an undirected graph G is a subgraph that is a tree which includes all of the vertices of G. In general, a graph may have several spanning trees, but a graph that is not connected will not contain a spanning tree (but see Spanning forests below). If all of the edges of G are also edges of a spanning tree T of G, then G is a tree and is identical to T (that is, a tree has a unique spanning tree and it is itself).


    Paste_Image.png

    如上图所示,生成树就是在给定的图中选取最少的边使所有顶点连通,那么最小生成树就是选取的边的权值和最小。


    了解了生成树的概念,就很容易能明白生成树只有n-1条边,其中n表示顶点数。
    那么怎么求最小生成树呢?
    这里我介绍kruscal算法。


    克鲁斯卡尔算法
    该算法用到的是贪心思想,将所有的边按权值排序,每次都选权值最小的边,然后判断这条边的两个顶点是否属于同一个连通块,如果不属于同一个连通块,那么这条边就应属于最小生成树,逐渐进行下去,直到连通块只剩下一个。


    kruscal算法的模板代码如下:

     1 const int maxn=400;//最大点数
     2 const int maxm=10000;//最大边数
     3 int n,m;//n表示点数,m表示边数
     4 struct edge{int u,v,w;} e[maxm];//u,v,w分别表示该边的两个顶点和权值
     5 bool cmp(edge a,edge b)
     6 {
     7     return a.w<b.w;
     8 }
     9 int fa[maxn];//因为需要用到并查集来判断两个顶点是否属于同一个连通块
    10 int find(int x)
    11 {
    12     if(x==fa[x]) return x;
    13     else return fa[x]=find(fa[x]);
    14 }
    15 int kruscal()
    16 {
    17     int ans=-1;
    18     sort(e+1,e+1+m,cmp);
    19     for(int i=1;i<=n;++i) fa[i]=i;//初始化并查集
    20     int cnt=n;
    21     for(int i=1;i<=m;++i)
    22     {
    23         int t1=find(e[i].u);
    24         int t2=find(e[i].v);
    25         if(t1!=t2)
    26         {
    27             if(cnt==1) break;
    28             fa[t1]=t2;
    29             ans=max(ans,e[i].w);
    30             cnt--;
    31         }
    32     }
    33     return ans;
    34 }

    针对这道题,我们只需要把ans+=e[i].w改为ans=max(ans,e[i].w)就好了,至此问题得到了解决。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=400;///最大点数
     4 const int maxm=10000;///最大边数
     5 int n,m;///n表示点数,m表示边数
     6 struct edge
     7 {
     8     int u,v,w;///u,v,w分别表示该边的两个顶点和权值
     9 }e[maxm];
    10 bool cmp(edge a,edge b)
    11 {
    12     return a.w<b.w;
    13 }
    14 int fa[maxn];///判断两个点是否属于同一个连通块
    15 int find(int x)
    16 {
    17     if(x==fa[x])
    18         return x;
    19     else return fa[x]=find(fa[x]);
    20 }
    21 int kruscal()
    22 {
    23     int ans=-1;
    24     sort(e+1,e+1+m,cmp);
    25     for(int i=1;i<=n;i++)
    26         fa[i]=i;///初始化并查集
    27     int cnt=n;
    28     for(int i=1;i<=m;i++)
    29     {
    30         int t1=find(e[i].u);
    31         int t2=find(e[i].v);
    32         if(t1!=t2)
    33         {
    34             if(cnt==1)
    35                 break;
    36             fa[t1]=t2;
    37             ///ans+=e[i].w;
    38             ans=max(ans,e[i].w);
    39             cnt--;
    40         }
    41     }
    42     return ans;
    43 }
    44 int main()
    45 {
    46     cin>>n>>m;
    47     for(int i=1;i<=m;i++)
    48     {
    49         cin>>e[i].u>>e[i].v>>e[i].w;
    50     }
    51     cout<<n-1<<" ";
    52     cout<<kruscal()<<endl;
    53     return 0;
    54 }
  • 相关阅读:
    iOS
    UI基本视图控制
    堆和栈的区别 ?
    单例模式
    Object-c的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方式用继承好还是分类好?为什么?
    id
    协议
    分类(类别)
    #import和#include以及@class三者的区别?
    内存管理
  • 原文地址:https://www.cnblogs.com/ECJTUACM-873284962/p/7141078.html
Copyright © 2011-2022 走看看