题目描述

  小$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. Linux操作系统目录一览表

    / // 根目录 /bin //存放必要的命令 比如ls.cp.mkdir等命令 /boot //存放内核以及启动所需的文件 /dev //存放硬件设备文件 比如声卡.磁盘.光驱 /etc //存放系 ...

  2. Linux 系统多台主机之间做SSH免密码登陆

    SSH 免密登录 环境说明 CentOS 7.3 关键点 免密登录的关键点在于理解谁登录谁. A 生成的公钥给 B,也给 C.D,则 A 可以直接免密 SSH 登录 B.C.D A 生成密钥 在 A ...

  3. Deepin15.10 python3安装、更新pip

    Deepin自带的Python3没有pip 需要安装一下: sudo apt install python3-pip更新pip sudo pip3 install --upgrade pip 然后运行 ...

  4. [DS+Algo] 005 三种简单排序及其代码实现

    目录 1. 冒泡排序 BubbleSort 1.1 算法描述 1.2 性能分析 1.3 Python 代码实现 2. 选择排序 SelectionSort 2.1 算法描述 2.2 选择排序的主要优点 ...

  5. [Luogu 5465] [LOJ 6435] [PKUSC2018]星际穿越(倍增)

    [Luogu 5465] [LOJ 6435] [PKUSC2018]星际穿越(倍增) 题面 n个点的图,点i和[l[i],i)的所有点连双向边.每次询问(l,r,x)表示x到[l,r]的所有点的最短 ...

  6. 好用的 Puppeteer 辅助工具 Puppeteer Recorder

    Puppeteer Puppeteer 是一个Node库,它提供了一个高级API来控制DevTools协议上的Chrome或Chromium,常用于爬虫.自动化测试等,你在浏览器手动完成的大多数事情都 ...

  7. Dva框架从初识到上手

    引言 最近工作需要用dva框架,同事帮我培训了一下,有一点点认识,在此总结. 当然,以后对dva可能会了解更透彻,文章会不断更新的.   初识 开始看架构代码,没有看文档的时候,不知道里面的几个关键字 ...

  8. Redis数据结构&命令手册

    Redis数据结构&命令手册 Redis数据结构 Redis可以存储键与5种不同数据结构之间的映射,这五种数据结构类型分别为STRING(字符串).LIST(列表).SET(集合).HASH( ...

  9. Java基础学习(2)

    Java基础学习(二) 面向对象 对象:客观存在的事物 面向对象:人具体关注的事物的某些信息 类:是模子,确定对象会拥有的特征(属性)和行为(方法) 对象的属性:对象具有的各种特征 对象的方法:对象能 ...

  10. 生成对抗网络 Generative Adversarial Networks

    转自:https://zhuanlan.zhihu.com/p/26499443 生成对抗网络GAN是由蒙特利尔大学Ian Goodfellow教授和他的学生在2014年提出的机器学习架构. 要全面理 ...