zoukankan      html  css  js  c++  java
  • 题解 P2872 【[USACO07DEC]道路建设Building Roads】

    这道题真的是令人窒息,Kruskal调了贼久一直RE,最后发现数组大小稍微少了那么一点点。(也就10倍吧。。)

    言归正传,根据本人的分析(以及算法标签的提示),这是一道求最小生成树的题目,当然要注意已经有一些路被建成了,因此他们直接标0即可

    下面是这道题用到了的所有(全局)变量。

    maxn, n, m就不解释了。

    x[]和y[]是用来储存农场的坐标的,当然也可以用二维数组写,只是我懒得敲那么多字(说起来差别也不大)。

    f是并查集中储存祖先的数组。

    如果有不了解的并查集的可以参考这一片讲解,个人认为十分通俗易懂。 传送门

    f1和f2是后面暂时储存有道路连接的农场的变量。

    top是Kruskal主体中记录最顶层的。

    cnt是记录长度的。

    ans我觉得也是废话(耶,皮这一下我很开心)。

    1 const int maxn = 1000001;
    2 
    3 int n, m;
    4 int x[maxn], y[maxn], f[maxn], f1, f2;
    5 int top = 0, cnt = 0;
    6 double ans = 0;

    接下来是储存两点距离的结构体,以及结构体排序。

     1 struct node {
     2     int x, y;
     3     double val; 
     4 }dis[maxn];
     5 
     6 bool cmp(node a, node b) {
     7     if(a.val == b.val)
     8         return a.x < b.x;
     9     return a.val < b.val;  
    10 }

    以及并查集模板(其中find函数使用了路径压缩)

     1 int find(int x) {  
     2     int r = x;  
     3     while(r != f[r]) r = f[r];  
     4     int i = x, j;  
     5     while(f[i] != r) {  
     6         j = f[i];  
     7         f[i] = r;  
     8         i = j;  
     9     }  
    10     return r;  
    11 }  
    12 
    13 void merge(int x, int y) {
    14     x = find(x);
    15     y = find(y);
    16     if(x != y) f[y] = x;
    17 }

     

    偶对了还有最没用的函数dt,用于求两点距离。

    1 double dt(int x1,int x2,int y1,int y2) {
    2     return sqrt(pow(double(x1 - x2), 2) + pow(double(y1 - y2), 2));
    3 }

    接下来果断开始主函数part。

    读入数据,别忘了初始化并查集。

     1 cin >> n >> m;
     2 for(int i = 1; i <= n; i++) cin >> x[i] >> y[i];
     3 for(int i = 1; i <= n; i++) f[i] = i;
     4 for(int i = 1; i <= n; i++)
     5     for(int j = i + 1; j <= n; j++) {
     6         dis[++cnt].x = i;
     7         dis[cnt].y = j;
     8         dis[cnt].val = dt(x[i], x[j], y[i], y[j]);
     9     }
    10 for(int i = 1; i <= m; i++) {
    11     cin >> f1 >> f2;
    12     dis[++cnt].x = f1;
    13     dis[cnt].y = f2;
    14     dis[cnt].val = 0;
    15 }

    然后给dis排个序。

     1 sort(dis + 1, dis + cnt + 1, cmp); 

    最重要的部分:Kruskal模板

    Kruskal算法将图中的每一个顶点视为一个独立的集合,首先将图中所有的边按权值大小从小到大排列,接着按顺序选择每一条边,如果这条边的两个端点不属于同一个集合,那么将它们所在的集合合并,同时将这条边加入E’。直到所有的顶点都属于同一个集合时,E’就是一颗最小生成树。

    --摘抄自《ACM国际大学生程序设计竞赛 知识与入门》

    1 for(int i = 1; i <= cnt; i++) {
    2     if(find(dis[++top].x) != find(dis[top].y)) {
    3         ans += dis[top].val;
    4         merge(dis[top].x, dis[top].y);
    5     }
    6 }

    最后,愉快的输出结果就好了,别忘了要保留两位小数。

  • 相关阅读:
    油猴脚本
    js hook
    js控制台原理检测
    安卓so文件函数动态注册
    js一些简单逆向题目实战
    js基础补充落下的知识点
    js反爬原理
    js容易让人眼瞎的写法
    js基础
    js一些常见非指纹built-in函数
  • 原文地址:https://www.cnblogs.com/ilverene/p/Luogu2872.html
Copyright © 2011-2022 走看看