码迷,mamicode.com
首页 > 其他好文 > 详细

最大流总结

时间:2016-09-06 21:26:37      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:

准备开始学习最大流。

持续更新。

(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

 

最大流总结

标签:

原文地址:http://www.cnblogs.com/wenruo/p/5847034.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!