[COGS 2401]Time is Money

Description

题库链接

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

\(1\leq n\leq 200,1\leq m\leq 10000\)

Solution

\(x=\sum_{e\in \mathbb{E}}e_c,y=\sum_{e\in \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}\times\vec{AC}\right)_{min}\) \[\begin{aligned}\vec{AB}\times\vec{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)+K\end{aligned}\]

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

然后继续分治对线段 \(AC\) 和线段 \(CB\) 求解即可。递归的边界为 \(\vec{AB}\times\vec{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('\n'))
#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;
}

转载于:https://www.cnblogs.com/NaVi-Awson/p/8523165.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 内容概要 《计算机试卷1》是一份综合性的计算机基础和应用测试卷,涵盖了计算机硬件、软件、操作系统、网络、多媒体技术等多个领域的知识点。试卷包括单选题和操作应用两大类,单选题部分测试学生对计算机基础知识的掌握,操作应用部分则评估学生对计算机应用软件的实际操作能力。 ### 适用人群 本试卷适用于: - 计算机专业或信息技术相关专业的学生,用于课程学习或考试复习。 - 准备计算机等级考试或职业资格认证的人士,作为实战演练材料。 - 对计算机操作有兴趣的自学者,用于提升个人计算机应用技能。 - 计算机基础教育工作者,作为教学资源或出题参考。 ### 使用场景及目标 1. **学习评估**:作为学校或教育机构对学生计算机基础知识和应用技能的评估工具。 2. **自学测试**:供个人自学者检验自己对计算机知识的掌握程度和操作熟练度。 3. **职业发展**:帮助职场人士通过实际操作练习,提升计算机应用能力,增强工作竞争力。 4. **教学资源**:教师可以用于课堂教学,作为教学内容的补充或学生的课后练习。 5. **竞赛准备**:适合准备计算机相关竞赛的学生,作为强化训练和技能检测的材料。 试卷的目标是通过系统性的题目设计,帮助学生全面复习和巩固计算机基础知识,同时通过实际操作题目,提高学生解决实际问题的能力。通过本试卷的学习与练习,学生将能够更加深入地理解计算机的工作原理,掌握常用软件的使用方法,为未来的学术或职业生涯打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值