hdu1575暢通工程再續【最小生成樹】cruskal&prim

暢通工程再續

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 19590    Accepted Submission(s): 6134


Problem 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就用快速排序按距離從小到大的順序排列,並把這些小島連接起來,並記錄建的橋數和橋的總長度,如果建的橋數等於c-1,那麼能連通,輸出最小花費,否則輸出 oh!。算出橋的總長度最後要記得乘單價100

 
【代碼】
cruskal:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int t,c,per[10000],x[110],y[110];
struct node
{
	int u,v;//u是起點,v是終點 
	double w;// w爲u、v之間的距離 ,注意爲double型 
}arr[10000];
int cmp(node x,node y)
{
	return x.w<y.w;//按距離從小到大排序 
}
double f(int x1,int x2,int y1,int y2)//定義函數f用來計算兩個島嶼之間的距離 
{
	return sqrt((double)((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)));
}
int find(int x)//尋找根節點 
{
	if(x==per[x])
	   return x;
	return per[x]=find(per[x]);
}
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		int i,j,count=1,sum=0;
		double ans=0;
		scanf("%d",&c);
		for(i=1;i<=c;i++)
			scanf("%d%d",&x[i],&y[i]);
		for(i=1;i<c;i++)
		{
			for(j=i+1;j<=c;j++)
		    {
		    	double d;
		    	d=f(x[i],x[j],y[i],y[j]);//求出兩點之間的距離 
		    	if(d>=10.0&&d<=1000.0)//如果符合建橋的條件 
			    {
				    arr[count].u=i;
				    arr[count].v=j;
				    arr[count].w=d;
				    count++;//節點數增加1 
			    }
			}
			
		}
		for(i=1;i<=count;i++)//初始化 
		   per[i]=i;
		sort(arr+1,arr+count,cmp);//排序 
		for(i=1;i<=count;i++)
		{
			int fx=find(arr[i].u);
			int fy=find(arr[i].v);
			if(fx!=fy)//合併 
			{
				sum++;
				per[fx]=fy;
				ans+=arr[i].w;
			}
		}
		if(sum==c-1)//能連通 
		   printf("%.1f\n",ans*100);//注意乘上單價 
		else
		   printf("oh!\n");
	}
	return 0;
}

prim:
#include <stdio.h>
#include <string.h>
#include <math.h>
#define N 110
#define MAX 1000
#define INF 0x3f3f3f3f
int n;
int x[N],y[N];//保存每個島的座標 
double g[N][N];//保存島與島之間的距離 

double dis(int i , int j)
{
	return sqrt( 1.0*((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])) );
}

void input()
{
    int i,j;
    scanf("%d",&n);
    for(i=1; i<=n; i++)
    scanf("%d%d",&x[i],&y[i]);//小島i的座標 

    for(i=1; i<=n; i++)
    for(j=1 ;j<=n; j++)
    {
		g[i][j]=g[j][i]=dis(i,j);//求出島嶼i j之間的距離 
    	if(g[i][j] < 10 || g[i][j] > 1000)//不符合要求的直接設爲無窮大 
		g[i][j] = g[j][i] = INF;
	}
	return ;
}

void prim()
{
    double dis[N],min,sum;
    int vis[N];
    int v,i,j,k;
	memset(vis, 0, sizeof(vis)); //初始化島嶼全爲未在點集合內 
    for(i=1; i<=n; i++)
	dis[i]=g[1][i];//記錄i點到集合1的距離 
    dis[1]=0;//本身到本身的距離爲0
	vis[1] = 1; //標記1已在集合內 
    for(v=1; v<n; v++)  //還要納入n-1個點
    {
        min=INF; 
		k=1;
        for(i=1; i<=n; i++)
        if(!vis[i] && dis[i] < min)//如果i點未在集合內  並且小於最小值 
        {
			min = dis[i];//記錄最小值 
			k = i;//記錄編號 
		}
		if(min == INF)
		{
			printf("oh!\n");
			return ;
		}
        vis[k] = 1;//標記爲已在集合內 
        for(i=1; i<=n; i++)//更新其餘點到集合1的距離 
        if(!vis[i] && dis[i] > g[k][i])//如果i未在集合1內並且 當前保存的i到集合的距離大於新更新的值 
        dis[i]=g[k][i];//更新最小值 
    }
    sum = 0;
	for(i = 2; i <= n; ++i)
	sum += dis[i] * 100.0;
	printf("%.1lf\n", sum);
    return ;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        input();
        prim();
    }
    return 0;
}


發佈了82 篇原創文章 · 獲贊 2 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章