神圣罗马帝国皇帝
题目描述
中世纪的德意志,战火纷飞。
近来
ZJ
、
JS
、
HN
、
SD
等地区为了扩大自己的版图面积,在内部分别举行了
ZJOI
、
JSOI
、
HNOI
以及
SDOI
(或者叫
SDTSC
) 选拔了许多优秀的战士准备发动一场波及到全国各处的战争——
NOI
!
在
HN
举行
HNOI
过程中,金天成,绰号光下巴(或者没胡子)红鼻子,二试怒翻盘的成绩强势成为
HN
大军的一员并被封为公爵,率领整个
HN
大军。
HN
这个地方早已不能让金天成满足了!
他在
NOI
之前发动了一场名为
PKUSC
的战役。
金天成凭借着强大的军事才能,卓越的领导能力,强势统一了德意志的大部分地区。
为他成为神圣罗马帝国的皇帝打下了坚实的基础!
现在,金天成需要加强自己统治区域内的运输,他现在有
N
块地盘,每块地盘之间都有些道路,总共有
金天成希望有一种方案,使得维护最少的道路让
N
块地盘两两之间存在通路。
并且选取出来的道路集合 S 的评估指数
最大!
由于他日理万机,所以这件事情他就让你来做了……
输入格式
第一行两个数字
N
,
接下来
M
行,每行三个数字
表示
A
、
输出格式
输出一行,表示所有道路选取方案中最大的评估指数。保留 6 位小数。
样例输入
3 3
1 2 2 3 2 3 1 1 1
样例输出
2.000000
样例解释
总共三种选法{边 1,边 2},{边 2,边 3},{边 3,边 1},然后评估值分别为
最大评估值为
2
。
数据范围
30%
的数据:
1≤N≤100
,
1≤M≤1000
。
100%
的数据:
1≤N≤104
,
1≤M≤5∗104
。
1≤C≤104
,
1≤D≤104
。
Solution
同 冒险岛。
首先二分答案
k
,则
即
所以求最小生成树就可以啦!
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,m,fa[10010],cnt;
const double maxn=1e+8*5;
struct Edge{int l,r,c,d;}edge[50010];
struct Rdge{int l,r;double c;}rdge[50010];
bool cmp(const Rdge &x,const Rdge &y){return x.c>y.c;}
int find(int x){
int tmp=x,pre;
while(tmp!=fa[tmp])tmp=fa[tmp];
while(x!=tmp){
pre=fa[x];fa[x]=tmp;x=pre;
}
return tmp;
}
bool judge(double x){
double sub=0;
for(int i=1;i<=m;i++){
rdge[i].l=edge[i].l; rdge[i].r=edge[i].r;
rdge[i].c=edge[i].c-edge[i].d*x;
}
for(int i=1;i<=n;i++)fa[i]=i;
sort(rdge+1,rdge+m+1,cmp); cnt=0;
for(int i=1;i<=m&&cnt<n-1;i++){
int fl=find(rdge[i].l),fr=find(rdge[i].r);
if(fl!=fr){cnt++;fa[fl]=fr;sub+=rdge[i].c;}
}
return sub>=0;
}
double binary(double l,double r){
while(r-l>=1e-8){
double mid=(l+r)/2;
if(judge(mid))l=mid;
else r=mid;
}
return l;
}
int main(){
freopen("emperor.in","r",stdin);
freopen("emperor.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d%d",&edge[i].l,&edge[i].r,&edge[i].c,&edge[i].d);
}
printf("%.6lf\n",binary(0,maxn));
return 0;
}