ecnu3247(铁路修复计划)

来源:互联网 发布:西安软件学校 编辑:程序博客网 时间:2024/04/29 13:54

题目链接:http://acm.ecnu.edu.cn/problem/3247/

显然,倍数越大最小生成树就越大,那么久二分答案好了。

为了防止每次kruskal的时候都要排序二导致复杂度升高,把边分成国内和国外两部分,分别排序,在 kruskal 的时候归并一下。

#include <iostream>#include <cstdio>#include <vector>#include <cstdlib>#include <algorithm>using namespace std;const int maxn = 1e5 + 10;typedef long long ll;struct Edge{    int u, v, w;    Edge(int u, int v, int w):u(u), v(v), w(w) {}};vector<Edge> edges;int f[maxn];int fa[maxn];int d[2][maxn];double t[maxn];int cnt[2] = {0,0};int n, m;ll M;int cmp(int a, int b){    return edges[a].w < edges[b].w;}int Find(int x){    if (fa[x] == x)        return fa[x];    fa[x] = Find(fa[x]);    return fa[x];}double kruskal(double k){    for (int i=1; i<=n; i++) fa[i] = i;    for (int i=0; i<cnt[0]; i++) t[d[0][i]] = (double)edges[d[0][i]].w;    for (int i=0; i<cnt[1]; i++) t[d[1][i]] = (double)edges[d[1][i]].w * k;    int i0 = 0;    int i1 = 0;    double ret = 0;    while (i0 < cnt[0] || i1 < cnt[1]) //归并    {        int tmp = 0;        if (i0 == cnt[0]) tmp = d[1][i1++];        else if (i1 == cnt[1]) tmp = d[0][i0++];        else        {            if (t[d[0][i0]] < t[d[1][i1]])                tmp = d[0][i0++];            else                tmp = d[1][i1++];        }        int fu = Find(edges[tmp].u);        int fv = Find(edges[tmp].v);        if (fu != fv)        {            ret += t[tmp];            fa[fu] = fv;        }    }    return ret;}int main(){    scanf("%d%d%lld", &n, &m, &M);    for (int i=0; i<m; i++)    {        int u, v, w;        scanf("%d%d%d%d", &u,&v,&w,&f[i]);        edges.push_back(Edge(u,v,w));        d[f[i]][cnt[f[i]]++] = i;    }    sort(d[0], d[0]+cnt[0],cmp);    sort(d[1], d[1]+cnt[1],cmp);    double l = 1, r = 1e15;    while (r-l > 0.0000001)    {        double mid = (l+r) / 2.0;        double mst = kruskal(mid);        if (mst < (double)M)            l = mid;        else            r = mid;    }    printf("%.6lf\n", l);    return 0;}