首页 > 代码库 > 最大流总结

最大流总结

准备开始学习最大流。

持续更新。

(hdu zoj poj vj 都挂了 还怎么刷题啊……)

326. Perspective

题意:一个小组有n个队伍1~n,每场比赛一个队伍赢,一个队伍输,现在已知每个队伍i都已经赢了Wi场比赛,同时知道每个队伍还需要打Ri场比赛,包括组内和组外,同时知道组内还剩下的比赛场数,Aij表示i和j还需要打几场比赛,Aij=Aji,∑(j:1~n)Aij <= Ri

问题是队伍1能否成为小组获胜场数最多的,可以并列第一。

题解:首先让队伍1赢得所有的比赛,其他队伍输掉所有组外的比赛。然后建图最大流。

技术分享
/* * 建一个源点 然后对于每一场比赛为一个点 从源点到比赛连边,权值为比赛的总分数 * 比赛这个点和比赛的两个队伍分别连边 权值大于等于比赛最大分数即可 * 每个队伍到汇点连一条边 权值应为该队伍和1队分数的差值(如果分数大于1队,应该直接输出no * 走一遍最大流 如果答案是所有比赛的分数和就可以满足要求 */#include <bits/stdc++.h>const int N = 1000;const int M = 1000000;const int INF = 1 << 30;struct Edge {    int to, next, w;} edge[M];int head[N], cntE;int src, sink;int pre[N], cur[N], dis[N], gap[N];int que[N], open, tail;void addedge(int u, int v, int w) {    edge[cntE].to = v;    edge[cntE].w = w;    edge[cntE].next = head[u];    head[u] = cntE++;    edge[cntE].to = u;    edge[cntE].w = 0;    edge[cntE].next = head[v];    head[v] = cntE++;}void BFS() {    int i, u, v;    memset(gap, 0, sizeof(gap));    memset(dis, -1, sizeof(dis));    open = tail = 0;    que[open] = sink;    dis[sink] = 0;    while (open <= tail) {        u = que[open++];        for (i = head[u]; i != -1; i = edge[i].next) {            v = edge[i].to;            if (edge[i].w != 0 || dis[v] != -1) continue;            que[++tail] = v;            ++gap[dis[v] = dis[u] + 1];        }    }}int sap(int n) { //编号从1开始 1~n    int i, v, u, flow = 0, aug = INF;    int flag;    BFS();    gap[0] = 1;    for (i = 1; i <= n; i++) cur[i] = head[i];    u = pre[src] = src;    while (dis[src] < n) {        flag = 0;        for (int j = cur[u]; j != -1; j = edge[j].next) {            v = edge[j].to;            if (edge[j].w > 0 && dis[u] == dis[v] + 1) {                flag = 1;                if (edge[j].w < aug) aug = edge[j].w;                pre[v] = u;                u = v;                if (u == sink) {                    flow += aug;                    while (u != src) {                        u = pre[u];                        edge[cur[u]].w -= aug;                        edge[cur[u] ^ 1].w += aug;                    }                    aug = INF;                }                break;            }            cur[u] = edge[j].next;        }        if (flag) continue;        int mindis = n;        for (int j = head[u]; j != -1; j = edge[j].next) {            v = edge[j].to;            if (edge[j].w > 0 && mindis > dis[v]) {                mindis = dis[v];                cur[u] = j;            }        }        if (--gap[dis[u]] == 0) break;        ++gap[dis[u] = mindis + 1];        u = pre[u];    }    return flow;}int w[N], r[N], a[N][N];int main() {    int n;    while (~scanf("%d", &n)) {        for (int i = 1; i <= n; ++i) scanf("%d", w+i);//每个队伍已经赢了多少场比赛        for (int i = 1; i <= n; ++i) scanf("%d", r+i);//每个队伍还可以打多少场比赛,包括本组和外组        for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) scanf("%d", &a[i][j]);//本组剩余比赛情况        w[1] += r[1]; //贪心 让本队全赢        bool fg = false;        for (int i = 2; i <= n; ++i) if (w[i] > w[1]) { fg = true; break; }        if (fg) { puts("NO"); continue; }        src = 1;        int cnt = n+1;        int sum = 0;        cntE = 0;        memset(head, -1, sizeof head);        for (int i = 2; i <= n; ++i) for (int j = i; j <= n; ++j) {            if (a[i][j] <= 0) continue;            sum += a[i][j];            addedge(src, cnt, a[i][j]);            addedge(cnt, i, INF);            addedge(cnt, j, INF);            cnt++;        }        sink = cnt;        for (int i = 2; i <= n; ++i) addedge(i, sink, w[1]-w[i]);        if (sap(sink) == sum) puts("YES");        else puts("NO");    }    return 0;}
View Code

 

最大流总结