首页 > 代码库 > 最大流总结
最大流总结
准备开始学习最大流。
持续更新。
(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;}
最大流总结
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。