【题解】【kruskal】
【因为要使生成树的边长和模长最大,那么只需每个复数在其方向向量的投影最大。so,可以把投影作为权值来做最大生成树。】
【kruskal的理论告诉我们:生成树的大小只与各边的相对边长有关,也就是说,只需考虑各边的大小关系尽量选权值大的边建生成树就行】
【考虑两边权值:
【枚举每一对边,算出两条边投影相等时极角的分界点,此时会把区间
【枚举每个区间,做最大生成树】
[复数处理时,和实数是相似的]
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
int x,y;
double a,b,way;
}d[410];
int fa[110],cnt,n,m;
double ans,f[80010];
int tmp(node p,node q)
{
return p.way>q.way;
}
int find(int x)
{
if(fa[x]==x) return fa[x];
fa[x]=find(fa[x]);
return fa[x];
}
inline double shorter(double x)
{
double cs=cos(x); double sn=sin(x);
for(int i=1;i<=m;++i) d[i].way=cs*d[i].a+sn*d[i].b;
sort(d+1,d+m+1,tmp);
for(int i=1;i<=n;++i)fa[i]=i;
double A=0,B=0;
for(int i=1,cnt=1;i<=m;++i)
{
int l1=find(d[i].x),l2=find(d[i].y);
if(l1!=l2)
{
A+=d[i].a; B+=d[i].b; fa[l1]=l2;
++cnt;
if(cnt==n) return (A*A+B*B);
}
}
}
inline void solve()
{
cnt=0; ans=-1;
for(int i=1;i<m;++i)
for(int j=i+1;j<=m;++j)
{
double x1=d[i].a,y1=d[i].b,x2=d[j].a,y2=d[j].b;
if(y1>y2) swap(x1,x2),swap(y1,y2);
if(y1==y2) {f[++cnt]=M_PI/2; f[++cnt]=-M_PI/2; continue;}
f[++cnt]=atan((x1-x2)/(y2-y1));
f[cnt+1]=f[cnt]+M_PI; cnt++;
}
f[++cnt]=-M_PI/2; f[++cnt]=M_PI*5/2;
sort(f+1,f+cnt+1);
cnt=unique(f+1,f+cnt+1)-f-1;
for(int i=1;i<=cnt;++i) ans=max(ans,shorter((f[i]+f[i-1])/2));
if(ans<0) printf("-1\n");
else printf("%.6lf\n",sqrt(ans));
return;
}
int main()
{
freopen("int.txt","r",stdin);
int i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=m;++i)scanf("%d%d%lf%lf",&d[i].x,&d[i].y,&d[i].a,&d[i].b);
solve();
return 0;
}