Uva 11478 - Halum(二分+差分约束)

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

【题意】
给定一张带权有向图,每次你可以选择一个结点v和一个整数d,把所有以v为终点的边的权值减少d,把所有以v为起点的边的权值增加d,最后要让所有边权最小值大于0且尽量大。对于每组数据输出边权最小值的最大值,如果无法让所有边权都大于0则输出”No Solution”,如果边权最小值可任意大,输出”Infinite”

【思路】
二分+差分约束系统,首先最小值最大让我们想到了二分答案,将问题转换为是否在所有操作完成后使得所有边的权值大于等于x,假设sum(u)为作用在结点u上的所有d之和,那么对于每条边(u,v),在操作完成后的权值就变成了w(u,v)+sum(u)-sum(v),要想满足假设的话则w(u,v)+sum(u)-sum(v)>=x,移项即sum(v)-sum(u)<=w(u,v)-x,对于每条边都是这样,于是构成了一个查分约束系统,利用BellmanFord来判断是否有解,有解则猜测的x成立,否则不成立。

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

const int inf = 0x3f3f3f3f;
const int maxn = 550;

struct Edge {
    int from, to, dist;
    Edge(int f, int t, int d) :from(f), to(t), dist(d) {}
};

struct BellmanFord {
    int n, m;
    vector<Edge> edges;
    vector<int> g[maxn];
    bool inq[maxn];
    int d[maxn];
    int p[maxn];
    int cnt[maxn];

    void init(int n) {
        this->n = n;
        for (int i = 0; i < n; ++i) g[i].clear();
        edges.clear();
    }

    void add(int from, int to, int dist) {
        edges.push_back(Edge(from, to, dist));
        m = edges.size();
        g[from].push_back(m - 1);
    }

    bool negativeCycle() {
        queue<int> que;
        memset(inq, 0, sizeof(inq));
        memset(cnt, 0, sizeof(cnt));
        for (int i = 0; i < n; ++i) { d[i] = 0; inq[i] = true; que.push(i); }
        while (!que.empty()) {
            int u = que.front();
            que.pop();
            inq[u] = false;
            for (int i = 0; i < g[u].size(); ++i) {
                Edge& e = edges[g[u][i]];
                if (d[e.to] > d[u] + e.dist) {
                    d[e.to] = d[u] + e.dist;
                    p[e.to] = g[u][i];
                    if (!inq[e.to]) {
                        que.push(e.to);
                        inq[e.to] = true;
                        if (++cnt[e.to] > n) return true;
                    }
                }
            }
        }
        return false;
    }
};

int n, m;
BellmanFord solver;

bool check(int x) {
    for (int i = 0; i < solver.m; ++i) {
        solver.edges[i].dist -= x;
    }
    bool ans = !solver.negativeCycle();
    for (int i = 0; i < solver.m; ++i) {
        solver.edges[i].dist += x;
    }
    return ans;
}

int main() {
    while (scanf("%d%d", &n, &m) == 2) {
        solver.init(n);
        int le = 1, ri = 0, mid;
        for (int i = 0; i < m; ++i) {
            int u, v, c;
            scanf("%d%d%d", &u, &v, &c);
            --u, --v;
            ri = max(ri, c);
            solver.add(u, v, c);
        }
        if (check(ri)) {
            printf("Infinite\n");
            continue;
        }
        if (!check(le)) {
            printf("No Solution\n");
            continue;
        }
        while (le + 1 < ri) {
            mid = (le + ri) >> 1;
            if (check(mid)) le = mid;
            else ri = mid;
        }
        printf("%d\n", le);
    }
    return 0;
}
posted @ 2018-02-14 15:20  不想吃WA的咸鱼  阅读(146)  评论(0编辑  收藏  举报