zoukankan      html  css  js  c++  java
  • P2872 [USACO07DEC]Building Roads S【kruskal】

    题目

     

     思路

    开始的思路就是使用kruskal不停选择最短的边加入最小生成树,但是我发现这道题不但没有给路径,而且知识给了一部分已经修建的路径,那么如何判断我们的最小生成树用不用某一条已经修好的边呢?是算上已经修建好的边之后答案最小还是有另外更小的路径呢??咋判断呢?

    问题一:没有路径:这道题人家给的是点的坐标,有了最表就可以求解距离,也就是说图中任何一点到任何一点的距离我们现在可以求了

    问题二:如何判断已修建的用不用:既然使用了kruskal算法,就需要将所有的边都求出来再进行比较,这时候我们就可以判断,如果此时某条边在计算它的长度时发现是已经修建好的,就把它的长度设为0

    最后使用算法寻找就行

    缺点

    这种方法需要在所有的边中寻找,其实就是在一个完全图中寻找,当边数较大的时候适合使用prim而不是kruskal,但是本题数据较小,所以可以过

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<string>
    #include<cstring>
    #include<vector>
    #include<cmath>
    using namespace std;
    #define maxm 1000001
    #define maxn 1010
    struct node
    {
        int from;
        int to;
        double dis;
    }e[maxm*2];//自己补的边
    struct point
    {
        double x;
        double y;
    
    }list[maxn];//点集
    bool cmp(struct node &a, struct node &b)
    {
        return a.dis < b.dis;
    }
    int father[maxn];
    int road[maxn][maxn];//记录已经修好的路
    int n, m, cnt = 0;
    double allcount = 0;//答案
    int find(int x)
    {
        if (father[x] == x)
            return x;
        return father[x] = find(father[x]);
    }
    
    int kruskal()
    {
        sort(e, e + cnt, cmp);
        for (int i = 0; i < cnt; i++)
        {
            int tempx = find(e[i].from);
            int tempy = find(e[i].to);
            if (tempx == tempy)continue;
            allcount += e[i].dis;
            father[tempx] = tempy;
        }
        return allcount;
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
            scanf("%lf%lf", &list[i].x, &list[i].y);
        for (int i = 1; i <= n; i++)father[i] = i;
        for (int i = 1; i <= m; i++)
        {
            int a, b;
            scanf("%d%d",&a, &b);
            road[a][b] = road[b][a] = 1;
        }
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= i; j++)//这里只需要补一半的边 1 2 300 ; 2 1 300 对本题意义一样
            {
                if (i == j)continue;
                e[cnt].from = j; e[cnt].to = i;
                if(road[i][j]==0)e[cnt].dis = sqrt((list[i].x - list[j].x)*(list[i].x - list[j].x) + (list[i].y- list[j].y)*(list[i].y-list[j].y));
                else e[cnt].dis = 0;
                cnt++;
            }
        }
        kruskal();
        printf("%.2lf", allcount);
    }
  • 相关阅读:
    oracle sql 优化大全
    MyBatis学习笔记
    Eclipse启动项目时,删除workspaces无用的工作区间
    java 中 BigDecimal 怎么与 0 比较
    Mybatis 异常: The content of elements must consist of well-formed character data or markup
    ODS与数据仓库
    MyBatis 缓存
    管理信息系统需求调研分析指南
    Merge Into 语句代替Insert/Update在Oracle中的应用实战
    Oracle数据库常用函数使用--持续更新中
  • 原文地址:https://www.cnblogs.com/Jason66661010/p/13171702.html
Copyright © 2011-2022 走看看