[CSP-S模拟测试]:小P的生成树(数学+Kruskal)
题目描述
小$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)的更多相关文章
- [CSP-S模拟测试]:小P的2048(模拟)
题目描述 最近,小$P$迷上了一款叫做$2048$的游戏.这块游戏在一个$n\times n$的棋盘中进行,棋盘的每个格子中可能有一个形如$2^k(k\in N^*)$的数,也可能是空的.游戏规则介绍 ...
- [CSP-S模拟测试]:小L的数(数位DP+模拟)
题目传送门(内部题132) 输入格式 第一行一个整数$t$. 接下来$t$行每行一个整数$n$. 输出格式 $t$行,每行一个整数表示答案. 样例 样例输入: 41818231232691052109 ...
- [CSP-S模拟测试]:小盆友的游戏(数学 or 找规律)
题目传送门(内部题110) 输入格式 第一行一个整数$N$,表示小盆友的个数. 第二行$N$个整数$A_i$,如果$A_i=-1$表示$i$目前是自由身,否则$i$是$A_i$的跟班. 输出格式 一个 ...
- [CSP-S模拟测试]:小P的单调数列(树状数组+DP)
题目描述 小$P$最近喜欢上了单调数列,他觉得单调的数列具有非常多优美的性质.经过小$P$复杂的数学推导,他计算出了一个单调增数列的艺术价值等于该数列中所有书的总和.并且以这个为基础,小$P$还可以求 ...
- [CSP-S模拟测试]:小奇的仓库(warehouse)(树形DP)
题目背景 小奇采的矿实在太多了,它准备在喵星系建个矿石仓库.令它无语的是,喵星系的货运飞船引擎还停留在上元时代! 题目描述 喵星系有$n$个星球,星球以及星球间的航线形成一棵树.从星球$a$到星球$b ...
- [CSP-S模拟测试]:小奇的矩阵(matrix)(DP+数学)
题目背景 小奇总是在数学课上思考奇怪的问题. 题目描述 给定一个$n\times m$的矩阵,矩阵中的每个元素$a_{i,j}$为正整数.接下来规定: $1.$合法的路径初始从矩阵左上角出发,每 ...
- [CSP-S模拟测试]:小奇挖矿2(DP+赛瓦维斯特定理)
题目背景 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿石交易市场,以便为飞船升级无限非概率引擎. 题目描述 现在有$m+1$个星球,从左到右标号为$0$到$n$,小奇最初 ...
- [CSP-S模拟测试]:小Y的图(最小生成树+LCA)
题目传送门(内部题131) 输入格式 第一行三个整数$n$.$m$和$Q$. 接下来$m$行每行三个整数$x$.$y$.$z$($1\leqslant x,y\leqslant n,1\leqslan ...
- [CSP-S模拟测试]:小W的魔术(数学 or 找规律)
题目传送门(内部题130) 输入格式 第一行一个整数$n$,表示字符串的长度. 第二行一个只包含小写字母的字符串$s$. 输出格式 一行一个整数表示答案对$998244353$取模后的结果. 样例 样 ...
随机推荐
- PHP7中的数据类型(一)计数引用、写时复制,可垃圾回收
列个简单的表格说明一下:
- windows 下mysql5.7设置密码
学习Springboot时用到mysql数据库,以前用的mysql5.6版本 基本百度一个教程即可,听说5.7有新改动,突然想试试于是找到解压版mysql5.7照常安装, 以前用的mysql5.6版本 ...
- angularJS(一):表达式、指令
简介 以 JavaScript 编写的库,是一个 JavaScript 框架 一.表达式 AngularJS 使用 表达式 把数据绑定到 HTML. 表达式写在双大括号内:{{ expression ...
- C# 同比缩放图片
/** * 无损缩放图片 * bitmap 需要缩放的图片 * w 需要缩放的宽度 * h 需要缩放的高度 * */ public static System.Drawing.Bitmap TBSca ...
- PHP curl拓展的介绍和使用
curl_setopt($ch, CURLOPT_URL, 'http://www.baidu.com/');//请求url地址curl_setopt($ch, CURLOPT_HEADER, 0); ...
- 04-A的LU分解
一.矩阵$AB$的逆 $(AB)^{-1}=B^{-1}A^{-1}$,顺序正好相反 二.$A=LU$ 如矩阵: $\left[\begin{array}{ll}{2} & {1} \\ {8 ...
- VB TreeView控件使用详解(有趣的示例)
第一小时:学习直接用代码将数据填充到树控件中. 为什么要先学习直接用代码将数据填充到树控件中?因为这种方法是最简单的,代码也最容易理解,学习树控件,先将这个学会,已经掌握了一半,所以先不要急着想怎么将 ...
- VB中输入函数InputBox的用法
格式:InputBox(pronpt[,title][,default][,xpos,ypos]).其中的pronpt为窗口的提示词,title为输入窗口的标题,default为输入窗口的默认内容,x ...
- ARP详解和ARP攻击
1.ARP简介 地址解析协议(Address Resolution Protocol),其基本功能为透过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的顺利进行.它是IPv4中网络层必不可少 ...
- Python 快排
def quick_sort(array,left,right): if left>=right: return low=left high=right key=array[low]#设置基准数 ...