您的位置:首页 > 其它

神圣罗马帝国皇帝

2016-07-10 15:22 381 查看

题目描述 Problem

题目描述只是借了历史的名义而已,纯属虚构娱乐,我亵渎历史我有罪。

中世纪的德意志,战火纷飞。 近来 ZJ、 JS、 HN、 SD 等地区为了扩大自己的版图面积,在内部分别举行了 ZJOI、 JSOI、 HNOI 以及 SDOI(或者叫 SDTSC)选拔了许多优秀的战士准备发动一场波及到全国各处的战争——NOI!

在 HN 举行 HNOI 过程中,金天成,绰号光下巴(或者没胡子) 红鼻子, 二试怒翻盘的成绩强势成为 HN 大军的一员并被封为公爵,率领整个 HN 大军。 HN 这个地方早已不能让金天成满足了!他在 NOI 之前发动了一场名为 PKUSC 的战役。 金天成凭借着强大的军事才能,卓越的领导能力, 强势统一了德意志的大部分地区。 为他成为神圣罗马帝国的皇帝打下了坚实的基础!

现在, 金天成需要加强自己统治区域内的运输,他现在有 N 块地盘,每块地盘之间都有些道路,总共有 M 条道路, 第 i 条道路有两个属性:运输量 Ci 、危险指数 Di 。 金天成希望有一种方案, 使得维护最少的道路让 N 块地盘两两之间存在通路。 并且选取出来的道路集合 S 的评估指数 Eval=∑i∈SCi∑i∈SDi

最大! 由于他日理万机,所以这件事情他就让你来做了……

输入描述 Input Description

第一行两个数字 N,M 。

接下来 M 行,每行三个数字 A,B,C,D(1≤A,B≤N) 。 表示 A,B 两块地盘之间有一条运输量为 C ,危险指数为 D 的可用通路。

输出描述 Output Description

输出一行,表示所有道路选取方案中最大的评估指数。 保留 6 位小数。

样例输入 Sample Input

3 3

1 2 2 1

2 3 2 1

3 1 1 1

样例输出 Sample Output

2.000000

提示 Hint

总共三种选法{边 1 ,边 2 },{边 2 ,边 3 },{边 3 ,边 1 } ,然后评估值分别为 2,1.5,1.5 。 最大评估值为 2 。

数据范围 Data Size

10% 的数据: 1≤N≤5,1≤M≤10 。

30% 的数据: 1≤N≤100,1≤M≤1000 。

100% 的数据: 1≤N≤104,1≤M≤5∗104。1≤C≤104,1≤D≤104 。

分析 I Think

当 Eval 值最大时也会存在评估指数小于 Eval 的,但不可能大于 Eval ,所以我们就二分答案,枚举 Eval ,在图中寻找最大生成树,如果边权之和大于 0 就可能,否则不可能。其中边权为 vi=Ci−Di∗Eval 由 Eval 的式子得出。

代码 Code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define cost(i) a[i].cost
#define u(i) a[i].u
#define v(i) a[i].v
#define val(i) a[i].val
#define wei(i) a[i].wei

struct node{
int u,v,wei,val;
double cost;
bool operator < (const node &h)const{
return cost>h.cost;
}
}a[55000];

int n,m;
int father[10500];

void read(int &);
double binary(double,double);
void updata(double);
double maxtree();
int find(int);
void uni(int,int);

int main(){

read(n);read(m);
for(int i=1;i<=m;++i){
read(u(i));read(v(i));read(val(i));read(wei(i));
}

printf("%.6lf",binary(0,10000));

return 0;

}

void read(int &_in){

_in = 0;
char ch = getchar();

while(ch>'9' || ch<'0')
ch = getchar();
while(ch<='9' && ch>='0'){
_in = _in*10+ch-'0';
ch = getchar();
}

}

double binary(double L,double R){

double M;

while(R-L > 1E-7){

M = (R+L)/2;
updata(M);

if(maxtree() > 0)
L = M;
else
R = M;

}

return L;

}

void updata(double r){

for(int i=1;i<=m;++i)
cost(i) = val(i)-r*wei(i);
for(int i=1;i<=n;++i)
father[i] = i;
sort(a+1,a+m+1);

}

double maxtree(){

double ans = 0;
for(int i=1,k=1;i<=m&&k<=n;++i)
if(find(u(i)) != find(v(i))){
uni(u(i),v(i));
ans += cost(i);
++k;
}

return ans;

}

int find(int x){

if(father[x] != x)
father[x] = find(father[x]);
return father[x];

}

void uni(int x,int y){

father[find(x)] = find(y);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: