Uva 11865 - Stream My Contest(二分+朱刘算法)

本文探讨了一道经典的图论问题:在有限预算下寻找有向图中从根节点到其他节点的路径,使得路径总长度最大且不超过指定成本。采用二分查找结合朱刘算法实现解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接 https://vjudge.net/problem/UVA-11865

【题意】
       有一张n个顶点,m条边的有向图,根节点为0。每条边有两个权值,一个是费用c,一个是长度b。问在总费用不超过cost的情况下选出若干条边,使得n个点连通时的边的最短长度的最大值是多少。

【思路】
       二分+朱刘算法,对最小带宽进行二分,看看能否只用大于等于最小带宽的网线连接所有机器同时不会超出预算费用

#include<bits/stdc++.h>
using namespace std;

const int inf = 2e9;
const int maxn = 100;
const int maxm = 10050;

int n, m, cost;
int le, ri, mid;
int in[maxn], pre[maxn];
int used[maxn], id[maxn];

struct Edge {
    int from, to, b, c;
    bool ok = true;
    Edge(int f = 0, int t = 0, int bb = 0, int cc = 0) :from(f), to(t), b(bb), c(cc) {}
}edges[maxm], cpy[maxm];

int direct_mst(int root, int V, int E) {
    int ans = 0;
    while (1) { 
        for (int i = 0; i < V; ++i) in[i] = inf;
        for (int i = 0; i < E; ++i) {
            if (!edges[i].ok) continue;
            int u = edges[i].from;
            int v = edges[i].to;
            if (in[v] > edges[i].c && u != v) {
                in[v] = edges[i].c;
                pre[v] = u;
            }
        }

        for (int i = 0; i < V; ++i) {
            if (i == root) continue;
            if (inf == in[i]) return -1;
        }

        int cnt = 0;
        memset(id, -1, sizeof(id)); 
        memset(used, -1, sizeof(used));
        in[root] = 0;
        for (int i = 0; i < V; ++i) {
            ans += in[i];
            int v = i;
            while (used[v] != i && id[v] == -1 && v != root) {
                used[v] = i;
                v = pre[v];
            }
            if (v != root && id[v] == -1) {
                for (int u = pre[v]; u != v; u = pre[u]) id[u] = cnt;
                id[v] = cnt++;
            }
        }

        if (0 == cnt) break;

        for (int i = 0; i < V; i++)
            if (id[i] == -1) id[i] = cnt++;

        for (int i = 0; i < E; i++) {
            if (!edges[i].ok) continue;
            int u = edges[i].from;
            int v = edges[i].to;
            edges[i].from = id[u];
            edges[i].to = id[v];
            if (id[u] != id[v]) edges[i].c -= in[v];
        }
        V = cnt;
        root = id[root];
    }
    return ans;
}

bool check(int x) {
    memcpy(edges, cpy, sizeof(edges));
    for (int i = 0; i < m; ++i) {
        if (edges[i].b >= x) edges[i].ok = true;
        else edges[i].ok = false;
    }
    int ans = direct_mst(0, n, m);
    return ans != -1 && ans <= cost;
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d%d", &n, &m, &cost);
        le = inf, ri = 0;
        for (int i = 0; i < m; ++i) {
            int u, v, b, c;
            scanf("%d%d%d%d", &u, &v, &b, &c);
            edges[i] = Edge(u, v, b, c);
            cpy[i] = edges[i];
            le = min(le, b);
            ri = max(ri, b);
        }
        if (!check(le)) {
            printf("streaming not possible.\n");
            continue;
        }
        while (le + 1 < ri) {
            mid = (le + ri) >> 1;
            if (check(mid)) le = mid;
            else ri = mid;
        }
        printf("%d kbps\n", le);
    }
    return 0;
}
用户表: Users +-------------+---------+ | Column Name | Type | +-------------+---------+ | user_id | int | | user_name | varchar | +-------------+---------+ user_id 是该表的主键(具有唯一值的列)。 该表中的每行包括用户 ID 和用户名。 注册表: Register +-------------+---------+ | Column Name | Type | +-------------+---------+ | contest_id | int | | user_id | int | +-------------+---------+ (contest_id, user_id) 是该表的主键(具有唯一值的列的组合)。 该表中的每行包含用户的 ID 和他们注册的赛事。 编写解决方案统计出各赛事的用户注册百分率,保留两位小数。 返回的结果表按 percentage 的 降序 排序,若相同则按 contest_id 的 升序 排序。 返回结果如下示例所示。 示例 1: 输入: Users 表: +---------+-----------+ | user_id | user_name | +---------+-----------+ | 6 | Alice | | 2 | Bob | | 7 | Alex | +---------+-----------+ Register 表: +------------+---------+ | contest_id | user_id | +------------+---------+ | 215 | 6 | | 209 | 2 | | 208 | 2 | | 210 | 6 | | 208 | 6 | | 209 | 7 | | 209 | 6 | | 215 | 7 | | 208 | 7 | | 210 | 2 | | 207 | 2 | | 210 | 7 | +------------+---------+ 输出: +------------+------------+ | contest_id | percentage | +------------+------------+ | 208 | 100.0 | | 209 | 100.0 | | 210 | 100.0 | | 215 | 66.67 | | 207 | 33.33 | +------------+------------+ 解释: 所有用户都注册了 208、209 和 210 赛事,因此这些赛事的注册率为 100% ,我们按 contest_id 的降序排序加入结果表中。 Alice 和 Alex 注册了 215 赛事,注册率为 ((2/3) * 100) = 66.67% Bob 注册了 207 赛事,注册率为 ((1/3) * 100) = 33.33%
03-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值