畅通工程再续

畅通工程再续 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Description

相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发 展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组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!
这一题醉醉的,题意很好懂,最小生成树,但是每个边权值必须在10~1000之内。否则就不能连,prim,kruscal都行。写之前一定要理好思路
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>

using namespace std;

#define N 110
#define INF 0xfffffff

struct node
{
    int x, y;
} P[N];

int vis[N];
double maps[N][N], dist[N];

void init()
{
    for(int i = 0; i < N; i++)
    {
vis[i] = 0;
        for(int j = 0; j < N; j++)
        {
            maps[i][j] = maps[j][i] = INF;
        }
    }
}
double prim(int n)
{
    vis[0] = 1;
    dist[0] = 0;
    int cou = 1;
    double ans = 0;

    for(int i = 0; i < n; i++)
        dist[i] = maps[0][i];

    for(int i = 0; i < n; i++)
    {
        int index, f;
        double Min = INF;
        index = f = 0;
        for(int j = 0; j < n; j++)
        {
            if(!vis[j] && dist[j] < Min)
                Min = dist[j], index = j, f = 1;   // 如果边权值满足题意,并且该点没有连接的话,f置为1,就把该值用上联通该点
        }
        if(f)
        {
            cou++;    //  cou计算已经被连接的点数,加一次边权值,联通点数加一
            vis[index] = 1;
            ans += Min;
        }


        for(int j = 0; j < n; j++)
        {
            if(!vis[j] && dist[j] > maps[j][index])
                dist[j] = maps[j][index];  // 最短路
        }
    }
    if(cou != n)
        return -1; 
    return ans;
}
int main()
{
    int t, c;

    cin >> t;

    while(t--)
    {
        cin >> c;

        init();

        for(int i = 0; i < c; i++)
            cin >> P[i].x >> P[i].y;

        for(int i = 0; i < c; i++)
        {
            for(int j = 0; j < c; j++)
            {
                int xx = P[i].x-P[j].x, yy = P[i].y-P[j].y;
                double q = sqrt(xx*xx+yy*yy);
                if(q >= 10 && q <= 1000)
                    maps[i][j] = maps[j][i] = q;  // 边权值即两点距离满足题意,就可以用,不然边权值就是INF,已初始化
            }
        }

        double ans = prim(c); 

        if(ans == -1)
            cout << "oh!" << endl;
        else
            printf("%.1f
", ans*100);
    }
    return 0;
}

      算法:Kruskal 和Prim 区别

*   Kruskal:将所有边从小到大加入,在此过程中
   判断是否构成回路
    –  使用数据结构:并查集
    –  时间复杂度:O(ElogE)
    –  适用于稀疏图
*   Prim:从任一节点出发,不断扩展
    –  使用数据结构:堆
    –  时间复杂度:O(ElogV) 或O(VlogV+E)(斐波那契堆)
    –  适用于密集图
                                               2
    –  若不用堆则时间复杂度为O(V  )

让未来到来 让过去过去
原文地址:https://www.cnblogs.com/Tinamei/p/4681089.html