再谈畅通工程

相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组RPRush对百岛湖的情况充分了解后,决定在符合条件的小岛间建上桥,所谓符合条件,就是2个小岛之间的距离不能小于10米,也不能大于1000米。当然,为了节省资金,只要求实现任意2个小岛之间有路通即可。其中桥的价格为 100元/米。

Input输入包括多组数据。输入首先包括一个整数T(T <= 200),代表有T组数据。 
每组数据首先是一个整数C(C <= 100),代表小岛的个数,接下来是C组坐标,代表每个小岛的坐标,这些坐标都是 0 <= x, y <= 1000的整数。 
Output每组输入数据输出一行,代表建桥的最小花费,结果保留一位小数。如果无法实现工程以达到全部畅通,输出”oh!”.Sample Input

2
2
10 10
20 20
3
1 1
2 2
1000 1000

Sample Output

1414.2
oh!

题目大意 :给你m个小镇的坐标,求能把它们连通起来的最小路径。

题目分析 :这算一个正正试试的最小生成树的题目了(即kruskal算法),之前写过一道题(还是畅通工程--题目来源),它是直接给了你两个小镇的距离并要求你连接起来,那是点集(变相的边集)来求的,因为它告诉了你

的起点和终点,同时告诉你两点间的权重。这样说来,那道题不过是最小生成数的缩小版。而今天才是真真正正的kruskal算法。

kruskal算法:包括三部分,起点位置(start),终点位置(end),权重(路的距离instance).其余的用并查集的知识即可。

题目收获 :kruskal的正是理解和掌握。

AC代码 :
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <math.h>
#define maxn 100+5
using namespace std;
int per[maxn];
double x[maxn],y[maxn];
struct node
{
    int Start,End;
    double instance;
    node():Start(0),End(0),instance(0){}
};


bool cmp(node x,node y)
{
    return x.instance<y.instance;
}
void init()
{
    for(int i=0;i<=maxn;i++)
        per[i]=i;
}

int FindSet(int x)
{
    if(x!=per[x])
        per[x]=FindSet(per[x]);
    return per[x];
}

bool UnionSet(int x,int y)
{
    int a=FindSet(x);
    int b=FindSet(y);
    if(a!=b)
        per[a]=b;
    else
        return false;
    return true;
}

void doit()
{
    init();
    memset(x,0,sizeof(x));
    memset(y,0,sizeof(y));
}


int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        doit();
        node bridge[6000];
        int a;cin >> a;
        for(int i=0;i<a;i++)
            cin >> x[i] >> y[i];
        int k=0;
        for(int i=0;i<a;i++)
            for(int j=i+1;j<a;j++)
        {
            double way=sqrt((double)(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
            if(way<10.0 || way>1000.0)
                continue;
            bridge[k].Start=i;
            bridge[k].End=j;
            bridge[k].instance=way;
            k++;
        }
        sort(bridge,bridge+k,cmp);
        double sum=0;
        for(int i=0;i<k;i++)
        {
            if(UnionSet(bridge[i].Start,bridge[i].End))
                sum+=bridge[i].instance;
        }

        int cut=0;
        for(int i=0;i<a;i++)
            if(i==per[i])
                cut++;
        if(cut==1)
            printf("%.1f\n",sum*100.0);
        else
            printf("oh!\n");
    }
    return 0;
}

 


posted @ 2017-08-07 15:11  Hunter丶安  阅读(120)  评论(0编辑  收藏  举报