题目描述

  小$P$是个勤于思考的好孩子,自从学习了最大生成树后,他就一直在想:能否将边权范围从实数推广到复数呢?可是马上小$P$就发现了问题,复数之间的大小关系并没有定义。于是对于任意两个复数$z_1,z_2$,小$P$定义$z_1<z_2$当且仅当$|z_1|<|z_2|$。
  现在,给出一张$n$个点$m$条边的简单无向带权图,小$P$想问你,如果按照他对复数大小的定义,这个图的最大生成树是什么?


输入格式

  输入的第一行为两个正整数$n$和$m$,分别表示这个无向图的点数和边数。
  接下来$m$行,每行四个整数$u,v,a,b(1\leqslant u,v\leqslant n,-1000\leqslant a,b\leqslant 1000)$,表示点$u$与点$v$之间有一条无向边,边权为$a+bi$。


输出格式

  输出仅有一个实数,它等于所有的最大生成树中所有边权之和的模长。
  实数四舍五入,保留六位小数。


样例

样例输入1:

3 3
1 2 1 3
2 3 2 2
3 1 3 1

样例输出1:

5.830952

样例输入2:

6 9
1 2 4 -1
2 3 4 1
3 4 -1 -5
1 5 -4 0
4 6 1 -6
2 6 -6 0
5 6 -7 5
2 4 7 1
1 4 -9 -5

样例输出2:

27.459060


数据范围与提示

样例$1$解释:

显然,从该图三条边中任取两条便可以构成一棵生成树,这三棵生成树的边权之和分别为$z_1=3+5i,z_2=4+4i,z_3=5+3i$,其中$|z_2|=\sqrt{32}<|z_1|=|z_3|=\sqrt{34}$。

数据范围:

对于$10\%$的数据:$n\leqslant 6$
对于$30\%$的数据:$n\leqslant 12$
对于另外$20\%$的数据:每条边的边权均为实数
对于$100\%$的数据:$n\leqslant 50,m\leqslant 200$,给定的无向图至少存在一个生成树

提示:

简单无向图的定义为:没有任何重边和自环的无向图。
若复数$z_1=a_1+b_1i,z_2=a_2+b_2i$,则$z_1+z_2=(a_1+a_2)+(b_1+b_2)i$。
设复数$z=a+bi$,符号$|z|=\sqrt{a^2+b^2}$表示该复数的模长。
若复数$z=a+bi$满足条件$b=0$,则该复数为实数。


题解

假设我们已经知道了生成树中各边求和所得复数的单位方向向量,那么要使得生成树的边权和模长最大,只需各复数在该方向向量上的投影之和最大。于是,我们将每条边对应的复数在该方向向量上的投影作为其新的权值,做一遍最大生成树即可解决。

但是显然我们不能枚举所有的方向向量。

但是根据$kruskal$的算法流程我们可以知道:

生成树的形态只与各边边权的相对大小有关,而与具体权值无关。

不妨设两条边,其边权分别是$x_1+y_1i$和$x_2+y_2i(y_1\neq y_2)$当两条边对应的复数投影相等时,方向向量$(\cos\theta,\sin\theta)$需要满足:$x_1\cos\theta+y_1\sin\theta=x_2\cos\theta+y_2\sin\theta$,化简后得$\tan\frac{x_1-x_2}{y_2-y_1}\Rightarrow\theta 1=\arctan\frac{x_1-x_2}{y_2-y_1},\theta 2=\arctan\frac{x_1-x_2}{y_2-y_1}+\pi$。而当$y_1=y_2,x_1\neq x_2$时,等式化为$x_1\cos\theta=x_2\cos\theta\Rightarrow \cos\theta=0\Rightarrow \theta 1=\frac{\pi}{2},\theta 2=\frac{3\pi}{2}$。

那么,我们可以枚举每一对边,算出两条边投影相等时计较的分解点,此时这些分解点会把$[-\frac{\pi}{2},\frac{3\pi}{2})$的极角分成若干个小区间。由于每条变得投影大小关于极角$\theta$是连续变化的,所以在每个小极角区间内,所有边的投影相对大小关系不变

于是我们可以对于每个区间任取一个方向向量做最大生成树,最后取最优方案即可。

需要注意的是因为$\arctan$无法求出$\frac{\pi}{2}$和$\frac{3\pi}{2}$,所以要插入这两个值。

时间复杂度:$\Theta(m^3\log m)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec{int x,y;double a,b,s;}e[201];
int n,m,cnt;
int fa[51];
double ans,theta[40001];
bool cmp(rec a,rec b){return a.s>b.s;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
double kruskal(double x)
{
int res=0;
double a=0.0,b=0.0;
for(int i=1;i<=m;i++)e[i].s=e[i].a*sin(x)+e[i].b*cos(x);
sort(e+1,e+m+1,cmp);
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++)
{
int x=find(e[i].x),y=find(e[i].y);
if(x==y)continue;
fa[x]=y;
res++;
a+=e[i].a;
b+=e[i].b;
if(res==n-1)break;
}
return a*a+b*b;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%lf%lf",&e[i].x,&e[i].y,&e[i].a,&e[i].b);
for(int i=1;i<=m;i++)
for(int j=i+1;j<=m;j++)
if(e[i].b==e[j].b)theta[++cnt]=M_PI/2.0;
else{theta[++cnt]=atan((e[i].a-e[j].a)/(e[j].b-e[i].b));theta[++cnt]=theta[cnt-1]+M_PI;}
theta[++cnt]=-M_PI/2.0;
theta[++cnt]=M_PI*3.0/2.0;
sort(theta+1,theta+cnt+1);
cnt=unique(theta+1,theta+cnt+1)-theta-1;
for(int i=1;i<=cnt;i++)ans=max(ans,kruskal(theta[i]));
printf("%.6lf",sqrt(ans));
return 0;
}

rp++

[CSP-S模拟测试]:小P的生成树(数学+Kruskal)的更多相关文章

  1. [CSP-S模拟测试]:小P的2048(模拟)

    题目描述 最近,小$P$迷上了一款叫做$2048$的游戏.这块游戏在一个$n\times n$的棋盘中进行,棋盘的每个格子中可能有一个形如$2^k(k\in N^*)$的数,也可能是空的.游戏规则介绍 ...

  2. [CSP-S模拟测试]:小L的数(数位DP+模拟)

    题目传送门(内部题132) 输入格式 第一行一个整数$t$. 接下来$t$行每行一个整数$n$. 输出格式 $t$行,每行一个整数表示答案. 样例 样例输入: 41818231232691052109 ...

  3. [CSP-S模拟测试]:小盆友的游戏(数学 or 找规律)

    题目传送门(内部题110) 输入格式 第一行一个整数$N$,表示小盆友的个数. 第二行$N$个整数$A_i$,如果$A_i=-1$表示$i$目前是自由身,否则$i$是$A_i$的跟班. 输出格式 一个 ...

  4. [CSP-S模拟测试]:小P的单调数列(树状数组+DP)

    题目描述 小$P$最近喜欢上了单调数列,他觉得单调的数列具有非常多优美的性质.经过小$P$复杂的数学推导,他计算出了一个单调增数列的艺术价值等于该数列中所有书的总和.并且以这个为基础,小$P$还可以求 ...

  5. [CSP-S模拟测试]:小奇的仓库(warehouse)(树形DP)

    题目背景 小奇采的矿实在太多了,它准备在喵星系建个矿石仓库.令它无语的是,喵星系的货运飞船引擎还停留在上元时代! 题目描述 喵星系有$n$个星球,星球以及星球间的航线形成一棵树.从星球$a$到星球$b ...

  6. [CSP-S模拟测试]:小奇的矩阵(matrix)(DP+数学)

    题目背景 小奇总是在数学课上思考奇怪的问题. 题目描述 给定一个$n\times m$的矩阵,矩阵中的每个元素$a_{i,j}$为正整数.接下来规定:    $1.$合法的路径初始从矩阵左上角出发,每 ...

  7. [CSP-S模拟测试]:小奇挖矿2(DP+赛瓦维斯特定理)

    题目背景 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿石交易市场,以便为飞船升级无限非概率引擎. 题目描述 现在有$m+1$个星球,从左到右标号为$0$到$n$,小奇最初 ...

  8. [CSP-S模拟测试]:小Y的图(最小生成树+LCA)

    题目传送门(内部题131) 输入格式 第一行三个整数$n$.$m$和$Q$. 接下来$m$行每行三个整数$x$.$y$.$z$($1\leqslant x,y\leqslant n,1\leqslan ...

  9. [CSP-S模拟测试]:小W的魔术(数学 or 找规律)

    题目传送门(内部题130) 输入格式 第一行一个整数$n$,表示字符串的长度. 第二行一个只包含小写字母的字符串$s$. 输出格式 一行一个整数表示答案对$998244353$取模后的结果. 样例 样 ...

随机推荐

  1. MySQL8 clone plugin

    安装MySQl8.0.17 下载 MySQL8.0.17 二进制版本 https://dev.mysql.com/downloads/mysql/ 解压,修改权限 -linux-glibc2.-x86 ...

  2. 剑指Offer编程题(Java实现)——删除链表中重复的结点

    题目描述 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3->4->4->5 处理后 ...

  3. Eureka 源码分析之 Eureka Server

    文章首发于公众号<程序员果果> 地址 : https://mp.weixin.qq.com/s/FfJrAGQuHyVrsedtbr0Ihw 简介 上一篇文章<Eureka 源码分析 ...

  4. SGU 521 North-East ( 二维LIS 线段树优化 )

    521. "North-East" Time limit per test: 0.5 second(s)Memory limit: 262144 kilobytes input: ...

  5. POJ 3259 Wormholes SPFA算法题解

    版权声明:本文作者靖心,靖空间地址:http://blog.csdn.net/kenden23/,未经本作者同意不得转载. https://blog.csdn.net/kenden23/article ...

  6. DataTable中如何去除重复的项 (获得某个字段中的不重复项)

    就是获取DataTable中某一列的值,因为从数据库中检索数据时,按照2个字段进行分组,而要获得的那一列刚好在分组这两列中,所以该列的值必然有重复,于是就想到了去除重复,有了思路以后在网上看了一些方法 ...

  7. 分布式锁实现方式介绍和Zookeeper实现原理

    分布式锁实现的几种方式 基于数据库实现分布式锁(表.数据库排他锁) 基于缓存(redis,memcached,tair) 基于Zookeeper实现分布式锁 关注点: 单点问题?(集群) 失效时间?( ...

  8. 【问题解决方案】visudo: /etc/sudoers is busy, try again later

    参考链接: 博客园:visudo: /etc/sudoers is busy, try again later CSDN:Shell 获取进程号并杀掉该进程 注:找到几篇相同的参考内容,都是只有查看进 ...

  9. 【学习总结】快速上手Linux玩转典型应用-第2章-linux简介

    课程目录链接 快速上手Linux玩转典型应用-目录 目录 1. 什么是Linux 2. Linux能够做什么事情 3. Linux的学习方法 4. 忘掉Windows的所有东西 1. 什么是Linux ...

  10. vue手动制作地址选择器

    方法一:4级地址选择器(基于elementui   Cascader 级联选择器) 推荐 效果图: 组件源码: <template> <div class="select- ...