zoukankan      html  css  js  c++  java
  • 洛谷P1547 Out of Hay

    题目背景

    奶牛爱干草

    题目描述

    Bessie 计划调查N (2 <= N <= 2,000)个农场的干草情况,它从1号农场出发。农场之间总共有M (1 <= M <= 10,000)条双向道路,所有道路的总长度不超过1,000,000,000。有些农场之间存在着多条道路,所有的农场之间都是连通的。

    Bessie希望计算出该图中最小生成树中的最长边的长度。

    输入输出格式

    输入格式:
    两个整数N和M。

    接下来M行,每行三个用空格隔开的整数A_i, B_i和L_i,表示A_i和 B_i之间有一条道路长度为L_i。

    输出格式:
    一个整数,表示最小生成树中的最长边的长度。

    输入输出样例

    输入样例#1:
    3 3
    1 2 23
    2 3 1000
    1 3 43
    输出样例#1:
    43

    【题解】
    发现神犇用的都是Kruskal算法,我就给大家另一种思路:Prim算法(求最小生成树的另一种方法)。

    首先,这道题是个裸的最小生成树模板题,与模板的唯一差别是:模板求的是最小生成树的各边的长度之和,而这道题求的是最小生成树的边的最大权。

    但是,虽然说这道题可以用Prim算法,但它的效率在这里比Kruskal算法差太多了(笔者跑两个算法,前者1266ms,后者16ms),所以我还是建议大家用Kruskal算法,我的程序只代表另一种思路。

    Kruskal算法以边为核心搜最小生成树,Prime算法以点为核心搜最小生成树,所以在点少时用Prim算法,点多时用Kruskal算法。

    不过,一般来说,Kruskal算法时间复杂度为O(nlongn),Prim算法时间复杂度为
    【邻接矩阵:O(v) 邻接表:O(elog2v)】,所以,打Kruskal大部分情况下是比较快的。

    模板程序改一句话即可A此题(既然是模板就不用解释了吧):

    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #define fp(i,a,b) for(i=a;i<=b;i++)
    #define fq(i,a,b) for(i=a;i>=b;i--)
    #define il inline
    #define re register
    #define ll long long 
    using namespace std;
    int map[5005][5005]={},dis[100005]={};
    bool vis[100005]={};
    il int gi()//读入优化
    {
      re int x=0;
      re short int t=1;
      re char ch=getchar();
      while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
      if(ch=='-') t=-1,ch=getchar();
      while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
      return x*t;
    }
    int main()
    {
      re int i,j,k,n,m,x,y,z,ans=0;
      memset(map,0x3f3f3f,sizeof(map));//这是给数组赋极大值的好方法
      n=gi();m=gi();
      fp(i,1,m)
      {
        x=gi();y=gi();z=gi();
        if(z<map[x][y]) map[x][y]=z,map[y][x]=z;
      }
      memset(dis,0x3f3f3f,sizeof(dis));
      fp(i,1,n) vis[i]=1;
      dis[1]=0;
      fp(i,1,n)
      {
        k=0;
        fp(j,1,n) if(vis[j]==1&&(dis[j]<dis[k])) k=j;
        vis[k]=0;
        fp(j,1,n) if(vis[j]==1&&(map[k][j]<dis[j])) dis[j]=map[k][j];
      }
      fp(i,1,n) ans=max(ans,dis[i]);//把求各边长度之和改为求边的最大长度
      printf("%d
    ",ans);
      return 0;
    }

    当然,更快的方法也要记录下来(Kruskal):

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
     using namespace std;
    struct tt
    {
        int from,to,cost;
    }a[10005];
    int father[2005];
    int k,n;
    int  find(int x)
    {
        if (father[x]==0) return x;
        return find(father[x]);
    }
    bool comp(tt a,tt b)
    {
        return a.cost<b.cost;
    }
    int main()
    {
        cin>>n>>k;
        for (int i=1;i<=k;i++)
            scanf("%d%d%d",&a[i].from,&a[i].to,&a[i].cost);
        sort(a+1,a+k+1,comp);
        int i=1,re=1;
        while(i<n)
        {
            int p=find(a[re].from);
            int q=find(a[re].to);
            if (p!=q)
            {
                i++;
                father[p]=q;
            }
            re++;
        }
        cout<<a[re-1].cost<<endl;
        return 0;
    }
  • 相关阅读:
    2018/12/06 L1-031 到底是不是太胖了 Java
    2018/12/06 L1-030 一帮一 Java
    2018/12/06 L1-029 是不是太胖了 Java
    .NET Framework 类库命名空间
    .NET获取根目录
    ddd领域驱动设计
    垃圾回收
    rest api
    数据库ACID
    事务隔离级别
  • 原文地址:https://www.cnblogs.com/yanshannan/p/7341797.html
Copyright © 2011-2022 走看看