bzoj1458
最小流
我很清楚知道自己已经忘记最小流怎么写了
是一个最小流,每行向每列连容量为1的边,源和汇分别向行和列连下界为限制,上界正无穷的边,然后就是跑最小流了。
我们先跑一个可行流,那么我们得先改造这个图,引入超级源汇,如果一个点流出去的比流进来的多,那么连向超级汇,否则超级源连过来,跑一遍dinic,这样得出了一个可行流,然后把汇向源连边,容量为inf,然后再跑一遍dinic,注意都是从超级源跑到超级汇,然后这条新建的边的反向边的流量就是最小流,原理不知道
#include<bits/stdc++.h> using namespace std; const int N = 310, inf = 1000000010; int head[N], d[N], q[N], iter[N], Map[N][N]; struct edge { int nxt, to, f; } e[N * N << 2]; int n, cnt = 1, source, sink, ans, m, k, sum1, sum2; int read() { int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return x * f; } void link(int u, int v, int f) { e[++cnt].nxt = head[u]; head[u] = cnt; e[cnt].to = v; e[cnt].f = f; } void insert(int u, int v, int f) { link(u, v, f); link(v, u, 0); } bool bfs() { queue<int> q; q.push(source); memset(d, 0, sizeof(d)); d[source] = 1; while(!q.empty()) { int u = q.front(); q.pop(); for(int i = head[u]; i; i = e[i].nxt) if(e[i].f && !d[e[i].to]) { d[e[i].to] = d[u] + 1; q.push(e[i].to); if(e[i].to == sink) return true; } } return false; } int dfs(int u, int delta) { if(u == sink || delta == 0) return delta; int ret = 0; for(int &i = iter[u]; i; i = e[i].nxt) if(e[i].f && d[e[i].to] == d[u] + 1) { int x = dfs(e[i].to, min(e[i].f, delta)); if(x == 0) d[e[i].to] = 0; e[i].f -= x; e[i ^ 1].f += x; delta -= x; ret += x; if(delta == 0) return ret; } return ret; } int dinic() { int ret = 0; while(bfs()) { for(int i = 0; i <= sink; ++i) iter[i] = head[i]; ret += dfs(source, inf); } return ret; } int main() { scanf("%d%d%d", &n, &m, &k); source = n + m + 2; sink = source + 1; for(int i = 1; i <= n; ++i) { int flow; scanf("%d", &flow); insert(0, i, inf); insert(source, i, flow); sum1 += flow; } insert(0, sink, sum1); for(int i = 1; i <= m; ++i) { int flow; scanf("%d", &flow); insert(i + n, n + m + 1, inf); insert(i + n, sink, flow); sum2 += flow; } insert(source, n + m + 1, sum2); while(k--) { int x, y; scanf("%d%d", &x, &y); Map[x][y] = 1; } for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) if(!Map[i][j]) insert(i, j + n, 1); dinic(); insert(n + m + 1, 0, inf); dinic(); ans = e[cnt].f; if(ans < max(sum1, sum2)) puts("JIONG!"); printf("%d\n", ans); return 0; }