zoukankan      html  css  js  c++  java
  • [COGS 2401]Time is Money

    Description

    题库链接

    给你 (n) 个节点 (m) 条边的无向连通图。每条边有两个权值 (c,t) ,要你生成一棵边集为 (mathbb{E}) 的生成树使得 [sum_{ein mathbb{E}}e_c imes sum_{ein mathbb{E}}e_t] 最小。

    (1leq nleq 200,1leq mleq 10000)

    Solution

    (x=sum_{ein mathbb{E}}e_c,y=sum_{ein mathbb{E}}e_t) 。记 (k=xy) ,那么对于反比例函数 (y=frac{k}{x})(k) 越小越贴近坐标轴。

    我们将所有生成树的权值以 ((x,y)) 的形式刻画在坐标轴上,显然满足条件的最小值一定在左下凸包上。

    那么首先最极端的是单纯按 (c) 排序和按 (t) 排序得到的点 (A,B)

    然后显然要找到在连线 (AB) 左下最远的点 (C)

    由于离 (AB) 最远的 (C) 必定导致 (S_{Delta ABC}) 最大。

    显然就是求 (left(vec{AB} imesvec{AC} ight)_{min}) [egin{aligned}vec{AB} imesvec{AC}&=(x_B-x_A)(y_C-y_A)-(y_B-y_A)(x_C-x_A)\&=y_C(x_B-x_A)+x_C(y_A-y_B)+Kend{aligned}]

    其中 (K) 是与 (C) 无关的量,可以忽略。所以将所有边权改为上述式子后做一遍最小生成树就可以求出 (C) 了。

    然后继续分治对线段 (AC) 和线段 (CB) 求解即可。递归的边界为 (vec{AB} imesvec{AC}geq 0)

    Code

    //It is made by Awson on 2018.3.7
    #include <bits/stdc++.h>
    #define LL long long
    #define dob complex<double>
    #define Abs(a) ((a) < 0 ? (-(a)) : (a))
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
    #define writeln(x) (write(x), putchar('
    '))
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    const int N = 200, M = 10000;
    void read(int &x) {
        char ch; bool flag = 0;
        for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
        for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
        x *= 1-2*flag;
    }
    void print(int x) {if (x > 9) print(x/10); putchar(x%10+48); }
    void write(int x) {if (x < 0) putchar('-'); print(Abs(x)); }
    
    int n, m, fa[N+5];
    struct tt {
        int u, v, w, c, t;
        bool operator < (const tt &b) const {return w < b.w; }
    }edge[M+5];
    struct node {
        int x, y;
        node(int _x = 0, int _y = 0) {x = _x, y = _y; }
        int operator * (const node &b) const {return x*b.y-y*b.x; }
        node operator + (const node &b) {node t; t.x = x+b.x, t.y = y+b.y; return t; }
        node operator - (const node &b) {node t; t.x = x-b.x, t.y = y-b.y; return t; }
        void print() {write(x), putchar(' '), writeln(y); }
    }ans, A, B;
    int find(int x) {return fa[x] ? fa[x] = find(fa[x]) : x; }
    
    void update(node &ans, node x) {if (1ll*ans.x*ans.y > 1ll*x.x*x.y || (1ll*ans.x*ans.y == 1ll*x.x*x.y && ans.x > x.x)) ans = x; }
    bool judge(node A, node B, node C) {return (B-A)*(C-A) >= 0; }
    node kruskal() {
        memset(fa, 0, sizeof(fa)); int cnt = 0; node tmp;
        sort(edge+1, edge+1+m);
        for (int i = 1; i <= m; i++) {
        if (find(edge[i].u)^find(edge[i].v)) {
            ++cnt; fa[find(edge[i].u)] = find(edge[i].v);
            tmp = tmp+node(edge[i].c, edge[i].t);
            if (cnt == n-1) break;
        }
        }
        return tmp;
    }
    void doit(node A, node B) {
        int x = B.x-A.x, y = A.y-B.y; node C;
        for (int i = 1; i <= m; i++) edge[i].w = x*edge[i].t+y*edge[i].c;
        update(ans, C = kruskal());
        if (judge(A, B, C)) return;
        doit(A, C), doit(C, B);
    }
    void work() {
        read(n), read(m);
        for (int i = 1; i <= m; i++) read(edge[i].u), read(edge[i].v), read(edge[i].c), read(edge[i].t), ++edge[i].u, ++edge[i].v;
        for (int i = 1; i <= m; i++) edge[i].w = edge[i].c;
        A = ans = kruskal();
        for (int i = 1; i <= m; i++) edge[i].w = edge[i].t;
        update(ans, B = kruskal());
        doit(A, B);
        ans.print();
    }
    int main() {
        work(); return 0;
    }
  • 相关阅读:
    原:Myeclipse10+Egit+bitbucket实现版本控制
    Myeclipse10使用git
    MyEclipse 10 下在线安装插件
    转:git windows中文目录乱码问题解决
    STUN和TURN技术浅析
    原:android4.2.2蓝牙源码阅读--bluedroid部分
    原创:超简单!windows配置NDK开发环境使用JNI
    c++对象的生命周期
    C++中虚析构函数的作用
    windows 命令行下 简单好用的查看端口占用情况的方法
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8523165.html
Copyright © 2011-2022 走看看