向前走莫回头❤

【bzoj 十连测】[noip2016十连测第九场]Problem C: 小P的生成树(kruskal+数学知识)

这里写图片描述
这里写图片描述
这里写图片描述

【题解】【kruskal】
【因为要使生成树的边长和模长最大,那么只需每个复数在其方向向量的投影最大。so,可以把投影作为权值来做最大生成树。】
【kruskal的理论告诉我们:生成树的大小只与各边的相对边长有关,也就是说,只需考虑各边的大小关系尽量选权值大的边建生成树就行】
【考虑两边权值:x1+yi1x2+yi2y1y2,当两边的复数的投影相等时,方向向量需要满足:x1cosθ+y1sinθ=x2cosθ+y2sinθ,化简后tanθ1=y2y1x1x2θ2=arctany2y1x1x2+π;而当x1x2y1=y2时,等式化为x1cosθ=x2cosθ=>cosθ=0=>θ1=π2θ2=3π2
【枚举每一对边,算出两条边投影相等时极角的分界点,此时会把区间[π23π2]分为若干个小区间,由于每条边的投影大小关于极角的变化是连续的,所以在每个小区间里权值的大小关系不发生改变。】
【枚举每个区间,做最大生成树】
[复数处理时,和实数是相似的]

#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;
}
posted @ 2016-11-17 10:10  lris0-0  阅读(143)  评论(0编辑  收藏  举报
过去的终会化为美满的财富~o( =∩ω∩= )m