畅通工程再续(prim)

相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组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!

  
  
    #include <stdio.h>  
    #include <string.h>  
    #include <math.h>  
    #include <algorithm>  
    using namespace std;  
    #define INF 0xfffffff  
    int n;  
    double d[105][105];  
    int vis[105];  
    double min;  
    double dis[105];   
    struct zb  
    {  
        int  x;  
        int y;  
    }a[105];  
    double dist(int i,int j)  
    {  
        return sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)*1.0+(a[i].y-a[j].y)*(a[i].y-a[j].y)*1.0);  
    }  
    void init()//初始化各个变量!   
    {  
        for(int i=1;i<=n;i++)  
        {  
            scanf("%d%d",&a[i].x,&a[i].y);  
        }  
        for(int i=1;i<=n;i++)  
        for(int j=1;j<=n;j++)//初始化d之后,一定要用d数组,而不能用算距离的,因为你用算距离的函数   
        {//不能够筛选在给定范围内的距离!   
            d[i][j]=d[j][i]=dist(i,j);  
            if(d[i][j]<10||d[i][j]>1000)  
               d[i][j]=d[j][i]=INF;  
        }//注意用d数组,而不能用距离函数,错了n次!   
        for(int i=1;i<=n;i++)//我们假设每个点到第1个点的距离为最小值!   
            dis[i]=d[1][i]; //代表第i个点到第1个点的距离!   
        memset(vis,0,sizeof(vis));//初始化,都没有进集合!   
             vis[1]=1;//第一个点先放到集合里面,然后将其他的点与集合里面的点求距离,将最小的距离的点放进集合!   
    }  
      
    int main()  
    {  
        int T,t;  
        double min;//注意是double型的!   
        scanf("%d",&T);  
        while(T--)  
        {  
            int k=1;  
            double s=0;  
            scanf("%d",&n);  
            init();  
            t=0;  
            for(int i=1;i<n;i++)//找n-1个点   
            {  
                min=INF;  
                for(int j=1;j<=n;j++)//找最小的距离   
                {  
                    if(!vis[j]&&(dis[j]<min))//第j个点到集合的距离的最小值!   
                    {  
                        min=dis[j];  
                        k=j;//保留最近的点到集合的距离的下标!   
                    }  
                }  
                if(min==INF)//如果所有的未标记的点到集合的距离为无穷大,(也就是把距离近的点都进到集合里面之后,剩下距离较大的点了,)   
                {//到集合的距离为无穷大,也就是那些不满足条件的点不能进集合,最终肯定不能形成一棵树!   
                      
                    break;  
                }  
                t++;  
                vis[k]=1;//距离集合最小的点进集合,并进行标记   
                s+=min;//并且将最小的距离加到s上!   
                for(int j=1;j<=n;j++)//对集合外的点到集合的距离进行更新!   
                {  
                    if(!vis[j]&&(dis[j]>d[j][k]))//如果加到集合里面的点距离集合外面的点的距离更近,就得将小的值赋值给dis[i]!   
                        dis[j]=d[j][k];  
                }  
            }  
            if(t==n-1)//判断是否都进集合里面,如果都进集合里面,则输出最小值!   
            {  
                printf("%.1lf\n",s*100);  
            }  
            else  
            printf("oh!\n");  
        }   
        return 0;  
    }   


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值