暢通工程再續
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 19590 Accepted Submission(s): 6134
每組數據首先是一個整數C(C <= 100),代表小島的個數,接下來是C組座標,代表每個小島的座標,這些座標都是 0 <= x, y <= 1000的整數。
【考察點】:最小生成樹
【解題思路】:計算每兩個小島之間的距離,如果大於10小於1000就用快速排序按距離從小到大的順序排列,並把這些小島連接起來,並記錄建的橋數和橋的總長度,如果建的橋數等於c-1,那麼能連通,輸出最小花費,否則輸出” oh!”。算出橋的總長度最後要記得乘單價100。
#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;
}
#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;
}