参考博客:
网络流–最大流(ek算法详解)
探网络流:dinic/EK算法学习笔记
文章目录
- 最大流:
- 题目:[Drainage Ditches](https://vjudge.net/problem/HDU-1532)
- 题目:[Escape](https://vjudge.net/problem/HDU-3605)
- 题目:[Task Schedule](https://vjudge.net/problem/HDU-3572#author=0)
- 题目:[Marriage Match II](http://acm.hdu.edu.cn/showproblem.php?pid=3081)
- 题目:[Dining](https://cn.vjudge.net/problem/POJ-3281)
- 题目:[Food](https://vjudge.net/problem/HDU-4292)
- 题目:[Marriage Match IV](https://vjudge.net/problem/HDU-3416)
- 最小费用最大流:
- 题目:[P3381 【模板】最小费用最大流](https://www.luogu.org/problem/P3381)
- 题目:[Going Home](http://acm.hdu.edu.cn/showproblem.php?pid=1533)
- 题目:[Farm Tour](https://vjudge.net/problem/POJ-2135#author=0)
- 题目:[Minimum Cost](https://cn.vjudge.net/problem/POJ-2516)
最大流:
题目:Drainage Ditches
纯模板题
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
const int INF = 1e7;
int cnt = 0, cost[maxn<<4], h[maxn<<4], to[maxn<<4], nex[maxn<<4];
int level[maxn];
queue<int>q;
int S, T, n, m;
void add(int x, int y, int z){
cost[cnt] = z;
to[cnt] = y;
nex[cnt] = h[x];
h[x]= cnt++;
}
bool bfs(){
queue<int>q;
memset(level,-1,sizeof(level));
level[S] = 0;
q.push(S);
while(!q.empty()){
int tp = q.front();
q.pop();
for(int i = h[tp]; i != -1; i = nex[i]){
int t = to[i];
if(level[t] == -1 && cost[i]){
level[t] = level[tp] + 1;
q.push(t);
if(t == T)return 1;
}
}
}
return 0;
}
int dfs(int u, int flow){
if(u == T)return flow;
int ret = flow, k;
for(int i = h[u]; i != -1 && ret; i = nex[i]){
int v = to[i];
if(cost[i] != 0&& level[u]+1 == level[v]){
k = dfs(v, min(cost[i], ret));
if(!k)level[v] = -1;
ret -= k;
cost[i] -= k;
cost[i^1] += k;
//if(flow == 0)break;
}
}
return flow - ret;
}
int dinic(){
int ans = 0, flow;
while(bfs())
while(flow = dfs(S, INF))
ans += flow;
return ans;
}
int main(){
while(~scanf("%d %d", &n, &m)){
memset(h, -1, sizeof h);
S = 1;
T = m;
for(int i = 1; i <= n; i++){
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
add(x, y, z);
add(y, x, 0);
}
printf("%d\n",dinic());
}
return 0;
}
题目:Escape
思路:本题的思路一看就非常简单就是在就是建一个网络流的图,所以我就这么写了,但是它T了,所有这么做思路是没有毛病的但是会超时的。有一个前提要求m<=10,所以可以考虑状态压缩,最多有1024种,所以可以考虑状态压缩。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e5+10;
const int INF = 2147483647;
int cnt = 0, cost[maxn], h[maxn], to[maxn], nex[maxn];
int level[maxn];
map<int, int> record;
queue<int>q;
int S, T, n, m;
void add(int x, int y, int z)
{
cost[cnt] = z;
to[cnt] = y;
nex[cnt] = h[x];
h[x]= cnt++;
cost[cnt] = 0;
to[cnt] = x;
nex[cnt] = h[y];
h[y] = cnt++;
}
inline int read()
{
char ch = getchar();
int x = 0, f = 1;
while(ch < '0' || ch > '9')
{
if(ch == '-') f = -1;
ch = getchar();
}
while('0' <= ch && ch <= '9')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
bool bfs()
{
queue<int>q;
memset(level,-1,sizeof(level));
level[S] = 0;
q.push(S);
while(!q.empty())
{
int tp = q.front();
q.pop();
for(int i = h[tp]; i != -1; i = nex[i])
{
int t = to[i];
if(level[t] == -1 && cost[i])
{
level[t] = level[tp] + 1;
q.push(t);
if(t == T)
return 1;
}
}
}
return 0;
}
int dfs(int u, int flow)
{
if(u == T)return flow;
int ret = flow, k;
for(int i = h[u]; i != -1 && ret; i = nex[i])
{
int v = to[i];
if(cost[i] != 0&& level[u]+1 == level[v])
{
k = dfs(v, min(cost[i], ret));
if(!k)level[v] = -1;
ret -= k;
cost[i] -= k;
cost[i^1] += k;
//if(flow == 0)break;
}
}
return flow - ret;
}
int dinic()
{
int ans = 0, flow;
while(bfs())
{
while(flow = dfs(S, INF))
ans += flow;
}
return ans;
}
int main()
{
int v;
while(~scanf("%d %d", &n, &m))
{
memset(h, -1, sizeof h);
S = 0;
cnt = 0;
int ret = 0;
record.clear();
for(int i = 1; i <= n; i++)
{
ret = 0;
for(int j = 1; j <= m; j++)
{
v = read();
if(v)ret += (v<<j);//状态压缩
}
record[ret]++;//同一种状态的人放在一块
}
int tot = 0, len = record.size();
for(auto &it:record)
{
tot++;
for(int i = 1; i <= m; i++)
{
if(it.first&(1<<i))
{
add(tot, len+i, it.second);
}
}
add(S, tot, it.second);
}
T = tot+m+1;
for(int i = 1; i <= m; i++)
{
v = read();
add(i+tot, T, v);
}
if(dinic() == n)printf("YES\n");
else printf("NO\n");
}
return 0;
}
题目:Task Schedule
思路:本题的思路就建一张网络图,源点为0,汇点为1+max+n,0到1~n的全职为pi,然后再分别建立i到si ~ ei的路径。
参考博客:hdu3572 最大流
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
const int INF = 1e7;
int cnt = 0, cost[maxn<<4], h[maxn<<4], to[maxn<<4], nex[maxn<<4];
int level[maxn];
queue<int>q;
int S, T, n, m;
void add(int x, int y, int z){
cost[cnt] = z;
to[cnt] = y;
nex[cnt] = h[x];
h[x]= cnt++;
}
bool bfs(){
queue<int>q;
memset(level,-1,sizeof(level));
level[S] = 0;
q.push(S);
while(!q.empty()){
int tp = q.front();
q.pop();
for(int i = h[tp]; i != -1; i = nex[i]){
int t = to[i];
if(level[t] == -1 && cost[i]){
level[t] = level[tp] + 1;
q.push(t);
if(t == T)return 1;
}
}
}
return 0;
}
int dfs(int u, int flow){
if(u == T)return flow;
int ret = flow, k;
for(int i = h[u]; i != -1 && ret; i = nex[i]){
int v = to[i];
if(cost[i] != 0&& level[u]+1 == level[v]){
k = dfs(v, min(cost[i], ret));
if(!k)level[v] = -1;
ret -= k;
cost[i] -= k;
cost[i^1] += k;
}
}
return flow - ret;
}
int dinic(){
int ans = 0, flow;
while(bfs())
while(flow = dfs(S, INF))
ans += flow;
return ans;
}
int main(){
int t;
scanf("%d", &t);
int ca = 0;
while(t--){
cnt = 0;
scanf("%d %d", &n, &m);
memset(h, -1, sizeof h);
int mm = -1, sum = 0;
S = 0;
for(int i = 1; i <= n; i++){
int p, s, e;
scanf("%d %d %d", &p, &s, &e);
add(S, i, p);
add(i, S, 0);
mm = max(mm, e);
sum += p;
for(int j = s;j <= e; j++){
add(i, n+j, 1);
add(n+j, i, 0);
}
}
int tp = n+mm+1;
for(int i = n+1; i < tp; i++){
add(i, tp, m);
add(tp, i, 0);
}
T = tp;
int res = dinic();
printf("Case %d: ", ++ca);
if(res == sum)puts("Yes");
else puts("No");
cout<<endl;
}
return 0;
}
题目:Marriage Match II
题意: 有N个女孩要与N个男孩玩配对游戏.每个女孩有一个可选男孩的集合(即该女孩可以选自己集合中的任意一个男孩作为该轮的搭档).
然后从第一轮开始,每个女孩都要和一个不同的男孩配对.如果第一轮N个女孩都配对成功,那么就开始第二轮配对,女孩依然从自己的备选男孩集合中选择,但是不能选那些已经被该女孩在前几轮选择中选过的男孩了(比如i女孩在第一轮选了j男孩,那么i在第二轮就不能选j男孩了). 问你游戏最多能进行多少轮?
思路:本题就是用二分去枚举轮数,然后建立超级源点和超级汇点,跑网络流。
参考博客:HDU 3081 Marriage Match II(二分+并查集+最大流)
本题因为数组开小了,一直TE,TE到生无可恋。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100100;//一定要开大点,一定开大点
const int INF = 1e7;
int cnt = 0, cost[maxn], h[maxn], to[maxn], nex[maxn];
int level[210], fa[210];
int dis[210][210];
int S, T, n, m;
inline void add(int x, int y, int z)
{
cost[cnt] = z;
to[cnt] = y;
nex[cnt] = h[x];
h[x]= cnt++;
}
inline int Find(int x)
{
return fa[x] == -1 ? x : fa[x]=Find( fa[x] );
}
inline bool bfs()
{
queue<int>q;
memset(level,-1,sizeof(level));
level[S] = 0;
q.push(S);
while(!q.empty())
{
int tp = q.front();
q.pop();
for(int i = h[tp]; i != -1; i = nex[i])
{
int t = to[i];
if(level[t] == -1 && cost[i])
{
level[t] = level[tp] + 1;
q.push(t);
if(t == T)return 1;
}
}
}
return 0;
}
inline int dfs(int u, int flow)
{
if(u == T)return flow;
int ret = flow, k;
for(int i = h[u]; i != -1 && ret; i = nex[i])
{
int v = to[i];
if(cost[i] != 0 && level[u]+1 == level[v])
{
k = dfs(v, min(cost[i], ret));
if(!k)level[v] = -1;
ret -= k;
cost[i] -= k;
cost[i^1] += k;
}
}
return flow - ret;
}
inline int dinic()
{
int ans = 0, flow;
while(bfs())
while(flow = dfs(S, INF))
ans += flow;
return ans;
}
inline void init()
{
memset(h, -1, sizeof h);
cnt = 0;
}
inline bool check(int n, int mid)
{
init();
for(int i = 1; i <= n; i++)
{
for(int j = n+1; j <= n*2; j++)
{
if(dis[i][j])
{
add(i, j, 1);
add(j, i, 0);
}
}
}
for(int i = 1; i <= n; i++)
{
add(S, i, mid);
add(i, S, 0);
}
for(int i = n+1; i < T; i++)
{
add(i, T, mid);
add(T, i, 0);
}
return dinic() == n*mid;
}
inline int bsearch_2(int l, int r, int n)
{
while (l < r)
{
int mid = (1+r+l)>>1;
if (check(n, mid)) l = mid;
else r = mid - 1;
}
return l;
}
int main()
{
int t, f, u, v;
scanf("%d", &t);
while(t--)
{
scanf("%d %d %d", &n, &m, &f);
memset(dis, 0, sizeof dis);
memset(fa, -1, sizeof fa);
for(int i = 1; i <= m; i++)
{
scanf("%d %d", &u, &v);
dis[u][v+n] = 1;
}
for(int i = 1; i <= f; i++)
{
int fx, fy;
scanf("%d %d", &u, &v);
fx = Find(u);
fy = Find(v);
if(fx != fy)fa[fx] = fy;
}
for(int i = 1; i <= n; i++)
{
for(int j = i+1; j <= n; j++)
{
if(Find(i) == Find(j))
{
for(int k = n+1; k <= 2*n; k++)
{
dis[i][k] = dis[j][k] = (dis[i][k] || dis[j][k]);
}
}
}
}
T = n*2+1;
S = 0;
int l = 0, r = n;
int ans = bsearch_2(l, r, n);
printf("%d\n", ans);
}
return 0;
}
题目:Dining
题意:一头牛可以选一杯喝的和食物,怎么使这个匹配最大。
思路:牛食物喝的匹配很容易想到二分图匹配,但是使这个匹配最大,所以就想到了最大流,但是如何建图呢,因为一个牛对应一个喝的和一份食物,所以我们想到把牛放中间,但是会存在一个问题,多个食物指向同一个牛,那么就不是我们想要的结果,所以就用到了拆点,把牛拆成两个点,这个使我们要的结果。
为什么拆点如图:
拆点之后:
代码:
//建图的思路 源点 >> 食物 >> 牛1 >> 牛11 >> 喝的 >> 汇点
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
const int maxn = 1e5+10;
const int INF = 1e7;
int cnt = 0, cost[maxn<<4], h[maxn<<4], to[maxn<<4], nex[maxn<<4];
int level[maxn];
queue<int>q;
int S, T, n, m, d;
void add(int x, int y, int z){
cost[cnt] = z;
to[cnt] = y;
nex[cnt] = h[x];
h[x]= cnt++;
cost[cnt] = 0;
to[cnt] = x;
nex[cnt] = h[y];
h[y] = cnt++;
}
bool bfs(){
queue<int>q;
memset(level,-1,sizeof(level));
level[S] = 0;
q.push(S);
while(!q.empty()){
int tp = q.front();
q.pop();
for(int i = h[tp]; i != -1; i = nex[i]){
int t = to[i];
if(level[t] == -1 && cost[i]){
level[t] = level[tp] + 1;
q.push(t);
if(t == T)return 1;
}
}
}
return 0;
}
int dfs(int u, int flow){
if(u == T)return flow;
int ret = flow, k;
for(int i = h[u]; i != -1 && ret; i = nex[i]){
int v = to[i];
if(cost[i] != 0&& level[u]+1 == level[v]){
k = dfs(v, min(cost[i], ret));
if(!k)level[v] = -1;
ret -= k;
cost[i] -= k;
cost[i^1] += k;
//if(flow == 0)break;
}
}
return flow - ret;
}
int dinic(){
int ans = 0, flow;
while(bfs())
while(flow = dfs(S, INF))
ans += flow;
return ans;
}
int main(){
while(~scanf("%d %d %d", &n, &m, &d)){
memset(h, -1, sizeof h);
S = 0;
T = n*2+m+d+1;
int k1, k2, v;
for(int i = 1; i <= m; i++)add(S, i, 1);//
for(int i = 1; i <= d; i++)add(n*2+m+i, T, 1);
for(int i = 1; i <= n; i++)add(m+i, n+m+i, 1);
for(int i = 1; i <= n; i++){
scanf("%d %d", &k1, &k2);
while(k1--){
scanf("%d", &v);
add(v, m+i, 1);
}
while(k2--){
scanf("%d", &v);
add(n+m+i, n*2+m+v, 1);
}
}
printf("%d\n",dinic());
}
return 0;
}
题目:Food
思路:这题的思想跟上面的差不多,稍微改改就行了,建图的方法都是一样的。
代码:
//建图思路 食物->>人1->>人11->>喝的
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
const int maxn = 1e5+10;
const int INF = 1e7;
int cnt = 0, cost[maxn<<4], h[maxn<<4], to[maxn<<4], nex[maxn<<4];
int level[maxn];
queue<int>q;
int S, T, n, m, d;
void add(int x, int y, int z)
{
cost[cnt] = z;
to[cnt] = y;
nex[cnt] = h[x];
h[x]= cnt++;
cost[cnt] = 0;
to[cnt] = x;
nex[cnt] = h[y];
h[y] = cnt++;
}
bool bfs()
{
queue<int>q;
memset(level,-1,sizeof(level));
level[S] = 0;
q.push(S);
while(!q.empty())
{
int tp = q.front();
q.pop();
for(int i = h[tp]; i != -1; i = nex[i])
{
int t = to[i];
if(level[t] == -1 && cost[i])
{
level[t] = level[tp] + 1;
q.push(t);
if(t == T)return 1;
}
}
}
return 0;
}
int dfs(int u, int flow)
{
if(u == T)return flow;
int ret = flow, k;
for(int i = h[u]; i != -1 && ret; i = nex[i])
{
int v = to[i];
if(cost[i] != 0&& level[u]+1 == level[v])
{
k = dfs(v, min(cost[i], ret));
if(!k)level[v] = -1;
ret -= k;
cost[i] -= k;
cost[i^1] += k;
//if(flow == 0)break;
}
}
return flow - ret;
}
int dinic()
{
int ans = 0, flow;
while(bfs())
while(flow = dfs(S, INF))
ans += flow;
return ans;
}
char a[1000];
int main()
{
while(~scanf("%d %d %d", &n, &m, &d))
{
memset(h, -1, sizeof h);
S = 0;
T = n*2+m+d+1;
int v;
for(int i = 1; i <= m; i++)
{
scanf("%d", &v);
add(S, i, v);
}
for(int i = 1; i <= d; i++)
{
scanf("%d", &v);
add(n*2+m+i, T, v);
}
for(int i = 1; i <= n; i++)add(m+i, n+m+i, 1);
for(int i = 1; i <= n; i++)
{
scanf("%s", a);
for(int j = 0; j < m; j++)
{
if(a[j] == 'Y')add(j+1, m+i,1);
}
}
for(int i = 1; i <= n; i++)
{
scanf("%s", a);
for(int j = 0; j < d; j++)
{
if(a[j] == 'Y')add(m+n+i,n*2+m+j+1, 1);
}
}
printf("%d\n",dinic());
}
return 0;
}
题目:Marriage Match IV
题意:就是给你一个图,问你这个图最多有多少条最短路。
思路:我最开始的思路就是跑一个最小费用最大流,对这个模板进行稍微的修改,但是一直T,找不到原因,我感觉可能是每一次跑最可能会超时,所以我就换了一种思想就是先跑一个最短路,然后把能够成最短路的所有边建一个网络流,权值为1,跑一个最大流就是结果。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
const int INF = 1e7;
int cnt = 0, cost[maxn<<4], h[maxn<<4], to[maxn<<4], nex[maxn<<4];
int head[maxn], v[maxn], w[maxn], Next[maxn], d[maxn], vis[maxn];
int tot = 0;
int level[maxn];
int S, T, n, m;
void add(int x, int y, int z)
{
cost[cnt] = z;
to[cnt] = y;
nex[cnt] = h[x];
h[x]= cnt++;
cost[cnt] = 0;
to[cnt] = x;
nex[cnt] = h[y];
h[y] = cnt++;
}
void add1(int u, int v1, int val)
{
v[tot] = v1;
w[tot] = val;
Next[tot] = head[u];
head[u] = tot++;
}
inline int read()
{
char ch = getchar();
int x = 0, f = 1;
while(ch < '0' || ch > '9')
{
if(ch == '-') f = -1;
ch = getchar();
}
while('0' <= ch && ch <= '9')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
void spfa()//纯spfa()模板
{
queue<int>q;
memset(d, 0x3f3f3f3f, sizeof d);
memset(vis, 0, sizeof vis);
d[S] = 0;
vis[S] = 1;
q.push(S);
while(q.size())
{
int x = q.front();
q.pop();
vis[x] = 0;
for(int i = head[x]; ~i; i = Next[i])
{
int y = v[i], z = w[i];
if(d[y] > d[x] + z)
{
d[y] = d[x] + z;
if(!vis[y])q.push(y), vis[y] = 1;
}
}
}
}
bool bfs()
{
queue<int>q;
memset(level,-1,sizeof(level));
level[S] = 0;
q.push(S);
while(!q.empty())
{
int tp = q.front();
q.pop();
for(int i = h[tp]; i != -1; i = nex[i])
{
int t = to[i];
if(level[t] == -1 && cost[i])
{
level[t] = level[tp] + 1;
q.push(t);
if(t == T)
{
return 1;
}
}
}
}
return 0;
}
int dfs(int u, int flow)
{
if(u == T)return flow;
int ret = flow, k;
for(int i = h[u]; i != -1 && ret; i = nex[i])
{
int v = to[i];
if(cost[i] != 0 && level[u]+1 == level[v])
{
k = dfs(v, min(cost[i], ret));
if(!k)level[v] = -1;
ret -= k;
cost[i] -= k;
cost[i^1] += k;
//if(flow == 0)break;
}
}
return flow - ret;
}
int dinic()//纯dinic模板,没有进行任何修改
{
int ans = 0, flow;
while(bfs())
{
while(flow = dfs(S, INF))
ans += flow;
}
return ans;
}
int main()
{
int a, b, c, t;
t = read();
while(t--)
{
memset(head, -1, sizeof head);
memset(h, -1, sizeof h);
cnt = 1;
tot = 1;
n = read();
m = read();
for(int i = 1; i <= m; i++)
{
a = read(), b = read(), c = read();//建图
if(a == b)continue;
add1(a, b, c);
}
S = read(), T = read();
spfa();
for(int i = 1; i <= n; i++)//找构成最短路的边
{
for(int j = head[i]; ~j; j = Next[j])
{
int k = v[j], z = w[j];
if(d[k] == d[i] + z)
{
add(i, k, 1);
}
}
}
printf("%d\n", dinic());
}
return 0;
}
最小费用最大流:
题目:P3381 【模板】最小费用最大流
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 5010;
const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
int ver[maxn], edge[maxn], cost[maxn], Next[maxn], head[maxn];
int d[N], incf[N], pre[N], v[N];
int n, k, tot, s, t, maxflow, ans;
void add(int x, int y, int z, int c){
ver[++tot] = y;//
edge[tot] = z;
cost[tot] = c;
Next[tot] = head[x];
head[x] = tot;
ver[++tot] = x;
edge[tot] = 0;
cost[tot] = -c;
Next[tot] = head[y];
head[y] = tot;
}
bool spfa(){
queue<int>q;
memset(d, INF, sizeof d);
memset(v, 0, sizeof v);
q.push(s);
d[s] = 0;
v[s] = 1;
incf[s] = INF;
while(q.size()){
int x = q.front();
v[x] = 0;
q.pop();
for(int i = head[x]; ~i; i = Next[i]){
if(!edge[i])continue;
int y = ver[i];
if(d[y] > d[x] + cost[i]){
d[y] = d[x] + cost[i];
incf[y] = min(incf[x], edge[i]);
pre[y] = i;
if(!v[y])v[y] = 1, q.push(y);
}
}
}
if(d[t] == INF)return false;
return true;
}
void update(){
int x = t;
while(x != s){
int i = pre[x];
edge[i] -= incf[t];
edge[i^1] += incf[t];
x = ver[i^1];
}
maxflow += incf[t];
ans += d[t]*incf[t];
}
int main(){
int a, b, c, d;
memset(head, -1, sizeof head);
scanf("%d %d %d %d", &n, &k, &s, &t);
tot = 1;
for(int i = 1; i <= k; i++){
scanf("%d %d %d %d", &a, &b, &c, &d);
add(a, b, c, d);
}
while(spfa())update();
printf("%d %d\n",maxflow, ans);
return 0;
}
题目:Going Home
思路:就是建图,然后跑最小费用最大流。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;;
const int maxn = 1e6+10;
const int INF = 0x3f3f3f3f;
int ver[maxn], edge[maxn], cost[maxn], Next[maxn], head[maxn];
int d[N], incf[N], pre[N], v[N];
int n, k, tot, s, t, maxflow, ans;
char str[105][105];
vector<pair<int, int> >h, m;
void add(int x, int y, int z, int c)
{
ver[++tot] = y;//
edge[tot] = z;
cost[tot] = c;
Next[tot] = head[x];
head[x] = tot;
ver[++tot] = x;
edge[tot] = 0;
cost[tot] = -c;
Next[tot] = head[y];
head[y] = tot;
}
bool spfa()
{
queue<int>q;
memset(d, INF, sizeof d);
memset(v, 0, sizeof v);
q.push(s);
d[s] = 0;
v[s] = 1;
incf[s] = INF;
while(q.size())
{
int x = q.front();
v[x] = 0;
//cout<<x<<endl;
q.pop();
for(int i = head[x]; ~i; i = Next[i])
{
if(!edge[i])continue;
int y = ver[i];
if(d[y] > d[x] + cost[i])
{
d[y] = d[x] + cost[i];
incf[y] = min(incf[x], edge[i]);
pre[y] = i;
if(!v[y])v[y] = 1, q.push(y);
}
}
}
if(d[t] == INF)return false;
return true;
}
void update()
{
int x = t;
while(x != s)
{
int i = pre[x];
edge[i] -= incf[t];
edge[i^1] += incf[t];
x = ver[i^1];
}
maxflow += incf[t];
ans += d[t]*incf[t];
}
int num(int i, int j)
{
return (i-1)*n+j;
}
int distance(int x1, int y1, int x2, int y2)
{
return abs(x1-x2)+abs(y1-y2);
}
int main()
{
int a, b, c, d;
while(scanf("%d %d", &n, &k) && n && k)
{
memset(head, -1, sizeof head);
h.clear();
m.clear();
tot = 1, ans = 0, maxflow = 0;
getchar();
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= k; j++)
{
scanf("%c", &str[i][j]);
}
getchar();
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= k; j++)
{
if(str[i][j] == 'H')h.push_back(make_pair(i, j));
if(str[i][j] == 'm')m.push_back(make_pair(i, j));
}
}
s = 0;
int x1, y1, x2, y2;
int len = m.size();
t = m.size()*h.size()+1;
for(int i = 0; i < m.size(); i++)
{
for(int j = 0; j < h.size(); j++)
{
x1 = m[i].first, y1 = m[i].second;
x2 = h[j].first, y2 = h[j].second;
int v = distance(x1, y1, x2, y2);
add(i+1,j+1+len, 1, v);
}
add(s, i+1, 1, 0);
}
for(int i = 0; i < h.size(); i++)
{
add(i+1+len, t, 1, 0);
}
while(spfa())update();
printf("%d\n",ans);
}
return 0;
}
题目:Farm Tour
注意:该题是双向图。
代码:
#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
const int N = 5010;
const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
int ver[maxn], edge[maxn], cost[maxn], Next[maxn], head[maxn];
int d[N], incf[N], pre[N], v[N];
int n, k, tot, s, t, maxflow, ans;
void add(int x, int y, int z, int c)
{
ver[++tot] = y;//
edge[tot] = z;
cost[tot] = c;
Next[tot] = head[x];
head[x] = tot;
ver[++tot] = x;
edge[tot] = 0;
cost[tot] = -c;
Next[tot] = head[y];
head[y] = tot;
}
bool spfa()
{
queue<int>q;
memset(d, INF, sizeof d);
memset(v, 0, sizeof v);
q.push(s);
d[s] = 0;
v[s] = 1;
incf[s] = INF;
while(q.size())
{
int x = q.front();
v[x] = 0;
q.pop();
for(int i = head[x]; ~i; i = Next[i])
{
if(!edge[i])continue;
int y = ver[i];
if(d[y] > d[x] + cost[i])
{
d[y] = d[x] + cost[i];
incf[y] = min(incf[x], edge[i]);
pre[y] = i;
if(!v[y])v[y] = 1, q.push(y);
}
}
}
if(d[t] == INF)return false;
return true;
}
void update()
{
int x = t;
while(x != s)
{
int i = pre[x];
edge[i] -= incf[t];
edge[i^1] += incf[t];
x = ver[i^1];
}
maxflow += incf[t];
ans += d[t]*incf[t];
}
int main()
{
int a, b, c;
while(~scanf("%d %d", &n, &k))
{
memset(head, -1, sizeof head);
tot = 1;
s = n+1;
t = n+2;
ans = 0;
maxflow = 0;
for(int i = 1; i <= k; i++)
{
scanf("%d %d %d", &a, &b, &c);
add(a, b, 1,c);
add(b, a, 1, c);
}
add(s, 1, 2, 0);
add(n, t, 2, 0);
while(spfa())update();
printf("%d\n",ans);
}
return 0;
}
题目:Minimum Cost
代码:
#include<string.h>
#include<iostream>
#include<stdio.h>
#include<queue>
#include<math.h>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 100;
const int maxn = 1e4+10;
const int INF = 0x3f3f3f3f;
int ver[maxn], edge[maxn], cost[maxn], Next[maxn], head[maxn];
int d[N], incf[N], pre[N], v[N];
int n, k, tot, s, t, maxflow, ans, m;
int shoper[N][N], supply[N][N];
int mpa[N][N][N];
int need1[N], need2[N];
void add(int x, int y, int z, int c)
{
ver[++tot] = y;//
edge[tot] = z;
cost[tot] = c;
Next[tot] = head[x];
head[x] = tot;
ver[++tot] = x;
edge[tot] = 0;
cost[tot] = -c;
Next[tot] = head[y];
head[y] = tot;
}
bool spfa()
{
queue<int>q;
memset(d, INF, sizeof d);
memset(v, 0, sizeof v);
q.push(s);
d[s] = 0;
v[s] = 1;
incf[s] = INF;
while(q.size())
{
int x = q.front();
v[x] = 0;
//cout<<x<<endl;
q.pop();
for(int i = head[x]; ~i; i = Next[i])
{
if(!edge[i])continue;
int y = ver[i];
if(d[y] > d[x] + cost[i])
{
d[y] = d[x] + cost[i];
incf[y] = min(incf[x], edge[i]);
pre[y] = i;
if(!v[y])v[y] = 1, q.push(y);
}
}
}
if(d[t] == INF)return false;
return true;
}
void update()
{
int x = t;
while(x != s)
{
int i = pre[x];
edge[i] -= incf[t];
edge[i^1] += incf[t];
x = ver[i^1];
}
maxflow += incf[t];
ans += d[t]*incf[t];
}
int num(int i, int j)
{
return (i-1)*n+j;
}
int distance(int x1, int y1, int x2, int y2)
{
return abs(x1-x2)+abs(y1-y2);
}
int main()
{
while(scanf("%d%d%d", &n, &m, &k), n != 0 || m != 0 || k != 0)
{
memset(need1, 0, sizeof need1);
memset(need2, 0, sizeof need2);
s = 0;
t = n+m+1;
memset(head, -1, sizeof head);
tot = 1, ans = 0;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= k; j++)
{
scanf("%d", &shoper[i][j]);
need1[j] += shoper[i][j];
}
for(int i = 1; i <= m; i++)
for(int j = 1; j <= k; j++)
{
scanf("%d", &supply[i][j]);
need2[j] += supply[i][j];
}
int f = 1;
for(int i = 1; i <= n; i++)
if(need1[i] > need2[i])
f = 0;
for(int i = 1; i <= k; i++)
for(int j = 1; j <= n; j++)
for(int l = 1; l <= m; l++)
scanf("%d", &mpa[i][j][l]);
if(f == 0) printf("-1\n");
else
{
for(int l = 1; l <= k; l++)
{
for(int i = 1; i <= m; i++)
add(0, i, supply[i][l], 0);
for(int i = m + 1; i <= m + n; i++)
add(i, m + n + 1, shoper[i-m][l], 0);
for(int i = 1; i <= m; i++)
for(int j = m + 1; j <= m + n; j++)
add(i, j, shoper[j-m][l], mpa[l][j-m][i]);
while(spfa())update();
memset(head, -1, sizeof head);
tot = 1;
}
printf("%d\n", ans);
}
}
return 0;
}