LA 1384 Stream My Contest(树形图 + 二分)

题意:你需要花费不超过cost元来搭建一个比赛网络,网络中有n台机器,编号0~n-1,其中机器0为服务器,其他机器为客户机。一共有m条可以使用的网线,其中第i条网线的发送端是机器ui,接收端是机器vi(数据只能从机器ui单向传输到机器vi),带宽是bi Kbps,费用是ci元。每台客户机应当恰好从一台机器接收数据,你的任务是最大化网络中的最小带宽。


思路:二分kbps建立树形图看是否满足条件,提前判断不受kbps最小值为所有边的最小权值条件下是否能够构成树形图,若不行则是impossible,否则二分kbps得出结构


#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
typedef long long ll;
const int maxn = 1e4 + 10;
const ll INF = 1e15 + 10;
using namespace std;

struct P {
    int u, v, b;
    ll c;
    P() {}
    P(int u, int v, int b, ll c) : u(u), v(v), b(b), c(c) {}
} p[maxn];
int L, R, nn, m, T, t = 1, limit;
int from, to, kb, cost;
ll d[100];
int id[100], par[100], vis[100];
vector<P> g;

bool operator < (P a, P b) {
    return a.c < b.c;
}

bool Dmst(int val, int root, int n) {
    ll ans = 0;
    for(int i = 0; i < m; i++) p[i] = g[i];
    while(1) {
        fill(d, d + 100, INF); d[root] = 0;
        memset(vis, -1, sizeof(vis));
        memset(id, -1, sizeof(id));
        for(int i = 0; i < m; i++) {
            if(p[i].b < val || p[i].u == p[i].v) continue;
            if(p[i].v == root || p[i].c >= d[p[i].v]) continue;
            d[p[i].v] = p[i].c; par[p[i].v] = p[i].u;
        }
        for(int i = 0; i < n; i++) {
            if(i == root) continue;
            if(d[i] == INF) return false;
        }
        int cnt = 0;
        for(int i = 0; i < n; i++) {
            ans += d[i];
            int v = i;
            while(vis[v] != i && id[v] < 0 && v != root) {
                vis[v] = i; v = par[v];
            }
            if(v == root || id[v] >= 0) continue;
            for(int u = par[v]; u != v; u = par[u]) id[u] = cnt;
            id[v] = cnt++;
        }
        if(!cnt) break;
        for(int i = 0; i < n; i++)
            if(id[i] < 0) id[i] = cnt++;
        for(int i = 0; i < m; i++) {
            int v = p[i].v;
            p[i].u = id[p[i].u];
            p[i].v = id[p[i].v];
            if(p[i].u != p[i].v) p[i].c -= d[v];
        }
        n = cnt; root = id[root];
    }
    return ans <= limit;
}

int low(int l, int r) {
    while(l < r) {
        int mid = l + ((r - l + 1) >> 1);
        bool res = Dmst(mid, 0, nn);
        if(!res) r = mid - 1;
        else l = mid;
    }
    return l;
}

int main() {
    scanf("%d", &T);
    while(T--) {
        g.clear();
        scanf("%d %d %d", &nn, &m, &limit);
        L = 1e9; R = 0;
        for(int i = 0; i < m; i++) {
            scanf("%d %d %d %d", &from, &to, &kb, &cost);
            g.push_back(P(from, to, kb, (ll)cost));
            R = max(R, kb); L = min(L, kb);
        }
        sort(g.begin(), g.end());
        bool can = Dmst(L, 0, nn);
        printf("Case %d: ", t++);
        if(!can) { printf("impossible\n"); continue; }
        int ans = low(L, R);
        printf("%d kbps\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值