您的位置:首页 > 其它

HDU 4081 Qin Shi Huang's National Road System(次小生成树-Kruskal)

2017-07-24 20:50 603 查看
Description

n个城市,每个城市有一个坐标(x[i],y[i])和一个居民数p[i],秦始皇想用n-1条道路把这n个城市连接起来,两个城市用直线段连接,要求任意两个城市互通且这n-1条道路的长度和最小,一个道士徐福说他可以把要修的n-1条道路中最长的那条道路给变出来,但秦始皇想让徐福把道路所连两个城市的居民数之和最大的那条道路变出来,所以秦始皇定义了一个值A/B,A是徐福变出的道路所连两个城市的居民数之和,B是剩下n-2条道路的长度之和,问A/B的最大值

Input

第一行一整数T表示用例组数,每组用例输入一个整数n表示城市数,之后输入n个城市的坐标和居民数x[i],y[i],p[i]

(T<=10,2 < n<=1000,0<=x[i],y[i]<=1000,0 < p[i] < 100000)

Output

输出A/B的最大值,结果保留到小数点后两位

Sample Input

2

4

1 1 20

1 2 30

200 2 80

200 1 100

3

1 1 20

1 2 30

2 2 40

Sample Output

65.00

70.00

Solution

对于一个固定的边u->v,A值固定,为使A/B最大需使B尽量小,所以求的是过u->v边的MST,先对原图求一遍MST,如果u->v这条边是树边则过这条边的MST就是不加限制的MST,如果不是,则从MST中u->v的路径中选取一条最长边删掉然后加入u->v这条边形成一个生成树即为过u->v这条边的MST,在Kruscal求MST的过程中维护len[u][v](MST上u到v路径上边权最大值),每次新加一条边x->y时,x所在连通块中的点u到y所在连通块中的点v的路径上边权最大值即为x->y这条边的边权(因为是把边按边权从小到大排序后再从小到大一条条插入的),求出MST后,设MST的权值和为mst,设答案为ans,对于权值为c的树边u->v有ans=min(ans,mst-c),对于非树边u->v有ans=min(ans,mst-len[u][v])

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 1111
#define maxm 1111111
struct node1
{
int u,v,flag;
double w;
}Edge[maxm];
struct node2
{
int to,next;
}Link[maxn];
int T,E,V,Fa[maxn],Head[maxn],End[maxn];
double len[maxn][maxn];
int cmp(node1 a,node1 b)
{
if(a.w!=b.w)return a.w<b.w;
if(a.u!=b.u)return a.u<b.u;
return a.v<b.v;
}
int find(int x)
{
if(Fa[x]==x) return x;
return Fa[x]=find(Fa[x]);
}
void unite(int x,int y)
{
x=find(x),y=find(y);
if(x==y) return ;
Fa[x]=y;
Link[End[y]].next=Head[x];
End[y]=End[x];
}
double kruskal()
{
int cnt=0;
double mst=0;
for(int i=1;i<=V;i++)
Link[i].to=i,Link[i].next=-1,Head[i]=i,End[i]=i;
sort(Edge,Edge+E,cmp);
for(int i=1;i<=V;i++)Fa[i]=i;
for(int k=0;k<E;k++)
{
int x=find(Edge[k].u),y=find(Edge[k].v);
if(x!=y)
{
for(int i=Head[x];~i;i=Link[i].next)
for(int j=Head[y];~j;j=Link[j].next)
{
int u=Link[i].to,v=Link[j].to;
len[u][v]=len[v][u]=Edge[k].w;
}
unite(x,y);
Edge[k].flag=1;
mst+=Edge[k].w;
cnt++;
if(cnt==V-1)return mst;
}
}
}
int x[maxn],y[maxn],p[maxn];
double get(int x1,int y1,int x2,int y2)
{
double x=x2-x1,y=y2-y1;
return sqrt(x*x+y*y);
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&V);
for(int i=1;i<=V;i++)scanf("%d%d%d",&x[i],&y[i],&p[i]);
E=0;
for(int i=1;i<=V;i++)
for(int j=i+1;j<=V;j++)
Edge[E].u=i,Edge[E].v=j,Edge[E].w=get(x[i],y[i],x[j],y[j]),Edge[E++].flag=0;
double mst=kruskal(),ans=0;
for(int i=0;i<E;i++)
{
int u=Edge[i].u,v=Edge[i].v,flag=Edge[i].flag;
double w=Edge[i].w;
if(flag)ans=max(ans,1.0*(p[u]+p[v])/(mst-w));
else ans=max(ans,1.0*(p[u]+p[v])/(mst-len[u][v]));
}
printf("%.2f\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: