2017年华东师范大学网络赛 G

G. 铁路修复计划
Time limit per test: 2.0 seconds
Time limit all tests: 15.0 seconds
Memory limit: 256 megabytes
Accept / Submit: 146 / 1219

在 A 国有很多城际铁路。这些铁路都连接两个城市(城市从 1 到 n 编号),可以双向通行,使得任意两个城市之间都由铁路网联系起来。

不过在一次星球大战之后,所有的铁路都经历了不同程度的损伤以至于无法通行了。由于经费紧缺,A 国政府不愿意再出资造新的铁路。对于原有的城际铁路,根据铁路的实际情况,有以下两种处理办法:

使用国内技术进行修复:主要针对损坏情况不是很严重的铁路。国内公司会对铁路状况进行评估,然后如实开出铁路修复的费用。
使用国外技术进行修复:主要针对损坏情况严重的铁路。国外公司也会对铁路情况进行评估,然后按照铁路实际修复费用的 k 倍来收费(其中 k 是一个由国外公司决定的实数,不管怎么说,优惠是不可能的,所以 k≥1)。
A国政府修复铁路的总预算是 M,目标是要让任意两个城市之间都能通过铁路联系起来。在预算不够且能够完成目标的条件下,显然没必要修复每一条铁路。

国外公司通过不知什么途径了解到了 A 国政府的总预算 M,他们现在要把 k 定下来,并且希望 k 尽可能得大。但 k 又不能太大,不然,如果 A 国政府发现无法完成任务的话,整个订单都会泡汤。

Input
测试数据包含不超过 30 个测试文件。每个测试文件是单个测试点。

第一行是三个整数 n,m,M (2≤n≤105,n−1≤m≤min{105,n(n−1)2},1≤M≤1015)。

接下来 m 行,每行四个整数 ui,vi,ti,fi。表示一条城际铁路,连接着 ui 和 vi 城市,ti 表示铁路实际修复费用。fi=1 表示只能由国外公司修复,fi=0 表示由国内公司修复。(1≤ui,vi≤n,ui≠vi,1≤ti≤106,fi∈{0,1})。输入保证两个城市之间不会存在多条铁路。

输入保证:

在国外公司不乱收费 (k=1) 的情况下,使用预算能完成要求。
完全不使用国外技术,只使用国内技术,是不能完成目标的。
Output
求 k 的最大值。输出答案与标准答案相差不超过 10−6 即判为正确。

Examples
input
3 3 9
1 2 1 1
1 3 2 0
2 3 1 1
output
7.000000
input
3 3 9
1 2 1 1
1 3 2 1
2 3 2 1
output
3.000000

题解: 二分答案 , 然后用Kruskal写判断就行了, 二分是写相等有三组数据错 , 加一减一却过了 ,这道题我错了N次。。

#include <bits/stdc++.h>
#define sc scanf
#define pr printf
using namespace std;
const int N = 110000;
struct Note
{
    int u , v , f;
    double cost , cost1;
}note[N];
int n , m ,  fa[N]; double fin_cost;
inline void init(double k);
bool kruskal(double k);
double binary_search_ans(double l , double r);
int find_fa(int x);
void union_xy(int x , int y);
bool cmp(Note &a , Note &b)
{
    //return b.cost- a.cost > 1e-9; //用这个就超时 , 无奈,在比赛的时候我是没想到一直TLE的原因就是这...
    return a.cost < b.cost;
}
int main()
{
    memset(note,0,sizeof(note));
    int i , j , u , v , t , f;
    sc("%d %d %lf",&n, &m , &fin_cost);
    for(i=1; i<=m; i++)
        sc("%d %d %lf %d",&note[i].u , &note[i].v , &note[i].cost1 , &note[i].f);
    pr("%06f\n",binary_search_ans(1 , 1e10));//范围纠结了很久
    return 0;
}
int find_fa(int x)
{
    if(fa[x] == x) return x;
    return fa[x] = find_fa(fa[x]);
}
void union_xy(int x , int y)
{
    int ax = find_fa(x);
    int ay = find_fa(y);
    if(ax != ay)
        fa[ax] = ay;
}
inline void init(double k)
{
    for(int i=1; i<=n; i++) fa[i] = i;

    for(int i=1; i<=m; i++)
    {
        if(note[i].f)
            note[i].cost = note[i].cost1*k;
        else
            note[i].cost = note[i].cost1;
    }
    sort(note+1 , note+1+m , cmp);
}
bool kruskal(double k)
{
    double sum = 0;
    init(k);
    for(int i=1; i<=m; i++)
    {
        int u = note[i].u;
        int v = note[i].v;
        if(find_fa(u) != find_fa(v))
        {
            sum += note[i].cost;
            union_xy(u,v);
        }
    }
    if(fin_cost - sum > 1e-9 )return 1;
    return 0;
}
double binary_search_ans(double l , double r)
{
    double ans , mid;
    for(int i=0; i<100; i++)
    {
        mid = (l+r)/2;
        if(!kruskal(mid))
            r = mid - 1;
        else
            l = mid + 1, ans = mid;
    }
    return ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值