zoukankan      html  css  js  c++  java
  • Luogu P1265修复公路【Prim最小生成树】By cellur925

    题目传送门

    政府审批的规则如下:

    (1)如果两个或以上城市申请修建同一条公路,则让它们共同修建;

    (2)如果三个或以上的城市申请修建的公路成环。如下图,A申请修建公路AB,B申请修建公路BC,C申请修建公路CA。则政府将否决其中最短的一条公路的修建申请;

    (3)其他情况的申请一律同意。

    题目说了一大堆,看起来就是在求最小生成树的。但是规则2有点难受,但是我们仔细想一想这个规则其实是没用的==。

    看到一个dalao是这样写的

    因为A申请修建公路AB,所以AB<=AC,B申请修建公路BC,所以BC<=AB,C申请修建公路CA,所以AC<=BC,而这三个条件同时成立当且仅当AB=BC=AC,既然这样,去掉那条边都是一样的,这与求解最小生成树不冲突。

    所以题目就是裸的最小生成树了,但是这道题给的是各点坐标,点数又是5000级别,那么边数就是n²的水平,因为我原来只会Kruskal(太菜了),而Kruskal是基于边的算法,复杂度O(mlogm),所以会超时==。于是现补了一下Prim算法,它是基于点的算法,复杂度O(n²),所以在这道题中就比较合适。

    而且如果用Kruskal的话,肯定要处理出所以边权的,而显然这样会MLE,所以这题就是Prim专属咯。

    口胡一下Prim算法:

    @ 算法思想:逐步扩展
    > 使用类似与 Dijkstra 算法的思想,逐步确定在生成树中的点;
    > 随便找一个起点,一开始只有起点是确定在生成树中的;
    > 在起点的邻居中找一个边权最短的,这条边就确定在生成树中了;
    > 再从没有确定的点中找一个距离确定的点中边权最小的,重复这个
    过程直到所有点被确定。
    @ 这个算法与 Dijkstra 的不同之处在于,找最小的时候,不再与起
    点的距离,而是和所有的确定点中的最小距离。
    (yl老师的课件)

    所以prim算法还是要学一学的啊==

    Code

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cmath> 
     4 #include<iostream>
     5 
     6 using namespace std;
     7 const int inf=0x7ffffff;
     8 
     9 int n,pos; 
    10 bool vis[6000];
    11 double ans,dis[6000];
    12 int x[6000],y[6000];
    13 
    14 double math_dis(int a,int b)
    15 {
    16     return sqrt((double)(x[a]-x[b])*(x[a]-x[b])+(double)(y[a]-y[b])*(y[a]-y[b]));
    17 }
    18 
    19 void Prim()
    20 {
    21     for(int i=1;i<=n;i++)
    22     {
    23         double sta=1e8;
    24         for(int j=1;j<=n;j++)
    25             if(!vis[j]&&dis[j]<sta)
    26             {
    27                 sta=dis[j];pos=j;
    28             }
    29         ans+=sta;
    30         vis[pos]=1;
    31         for(int j=1;j<=n;j++)
    32         {
    33             double tmp=math_dis(pos,j);
    34         //    cout<<tmp<<endl;
    35             if(tmp<dis[j]) dis[j]=tmp;
    36         }
    37     }
    38 }
    39 
    40 int main()
    41 {
    42     scanf("%d",&n);
    43     for(int i=1;i<=n;i++)
    44     {
    45         scanf("%d%d",&x[i],&y[i]);
    46         dis[i]=1e8;
    47     }
    48     dis[1]=0;
    49     Prim();
    50     printf("%.2lf",ans);
    51     return 0;
    52 }
    View Code
  • 相关阅读:
    解决 Android SDK Manager不能下载旧版本的sdk的问题
    [置顶] 如何合并文件中的内容?
    JSTL解析——005——core标签库04
    C中的几组指针
    别动我的奶酪:CSV文件数据丢零现象及对策
    重载(overload),覆盖/重写(override),隐藏(hide)
    IOS 轻量级数据持久化 DataLite
    记录路径dp-4713-Permutation
    android 多媒体数据库详解
    Data Recovery Advisor(数据恢复顾问)
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9665130.html
Copyright © 2011-2022 走看看