魍魉的小窝


  • 首页

  • 标签

  • 分类

  • 归档

  • 关于

  • 搜索

网络流模板集合

发表于 2018-07-14 | 分类于 OI
字数统计: 1,751 | 阅读时长 ≈ 11
  • EK

动能算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include<cstdio>
#include<queue>
using namespace std;
const int M=100050,N=10050,INF=1<<25;
int n,m,st,ed,head[N],cnt=0,pre[N],d[N];
struct edge{int to,next,flow,cap;} e[M<<1];
queue<int> Q;
inline int read()
{
register int x=0,t=1;
register char ch=getchar();
while (ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if (ch=='-') t=-1,ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
void add(int u,int v,int cap)
{
e[cnt].next=head[u];
head[u]=cnt;
e[cnt].to=v;
e[cnt++].cap=cap;
}
void update(int x,int to,int flow)
{
for(int i=x;i!=to;i=e[pre[i]^1].to)
{
e[pre[i]].flow+=flow;
e[pre[i]^1].flow-=flow;
}
}
int bfs(int s,int t)
{
while (!Q.empty()) Q.pop();
for(int i=1;i<=n;i++) d[i]=0;
d[s]=INF,Q.push(s);
while (!Q.empty()&&!d[t])
{
int x=Q.front();Q.pop();
for(int i=head[x];~i;i=e[i].next)
{
int to=e[i].to;
if (!d[to]&&e[i].flow<e[i].cap)
{
pre[to]=i;
d[to]=min(d[x],e[i].cap-e[i].flow);
Q.push(to);
}
}
}
return d[t];
}
int EK(int s,int t)
{
int ret=0,new_flow;
while (new_flow=bfs(s,t))
{
ret+=new_flow;
update(t,s,new_flow);
}
return ret;
}
int main()
{
n=read(),m=read();
st=read(),ed=read();
for(int i=1;i<=n;i++) head[i]=-1;
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
add(u,v,read());
add(v,u,0);
}
printf("%d",EK(st,ed));
return 0;
}

  • Dinic

比EK快很多的Dinic

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include<cstdio>
#include<queue>
using namespace std;
const int M=120050,N=10050,INF=1<<25;
int n,m,st,ed,head[N],cnt=0,d[N],cur[N];
struct edge{int to,next,flow,cap;} e[M<<1];
queue<int> Q;
inline int read()
{
register int x=0,t=1;
register char ch=getchar();
while (ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if (ch=='-') t=-1,ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
void add(int u,int v,int cap)
{
e[cnt].next=head[u];
head[u]=cnt;
e[cnt].to=v;
e[cnt++].cap=cap;
}
int bfs(int s,int t)
{
while (!Q.empty()) Q.pop();
for(int i=1;i<=n;i++) d[i]=0;
d[s]=1,Q.push(s);
while (!Q.empty()&&!d[t])
{
int x=Q.front();Q.pop();
for(int i=head[x];~i;i=e[i].next)
{
int to=e[i].to;
if (e[i].flow<e[i].cap&&!d[to])
{
d[to]=d[x]+1;
Q.push(to);
}
}
}
return d[t];
}
int dfs(int x,int t,int flow)
{
if (!flow||x==t) return flow;
int ret=0,new_flow;
for(int &i=cur[x];~i&&flow;i=e[i].next)
{
int to=e[i].to;
if (d[x]+1==d[to])
{
new_flow=dfs(to,t,min(flow,e[i].cap-e[i].flow));
e[i].flow+=new_flow;
e[i^1].flow-=new_flow;
ret+=new_flow;
flow-=new_flow;
}
}
return ret;
}
int Dinic(int s,int t)
{
int ret=0;
while (bfs(s,t))
{
for(int i=1;i<=n;i++) cur[i]=head[i];
ret+=dfs(s,t,INF);
}
return ret;
}
int main()
{
n=read(),m=read();
st=read(),ed=read();
for(int i=1;i<=n;i++) head[i]=-1;
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
add(u,v,read());
add(v,u,0);
}
printf("%d",Dinic(st,ed));
return 0;
}

  • ISAP

ISAP+GAP优化+当前弧优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include<cstdio>
#include<queue>
using namespace std;
const int M=100050,N=10050,INF=1<<25;
int n,m,st,ed,head[N],cnt=0,d[N],num[N],pre[N],cur[N];
struct edge{int to,next,flow,cap;} e[M<<1];
queue<int> Q;
inline int read()
{
register int x=0,t=1;
register char ch=getchar();
while (ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if (ch=='-') t=-1,ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
void add(int u,int v,int cap)
{
e[cnt].next=head[u];
head[u]=cnt;
e[cnt].to=v;
e[cnt++].cap=cap;
}
void bfs(int s)
{
for(int i=1;i<=n;i++) d[i]=n;
d[s]=0,Q.push(s);
while (!Q.empty())
{
int x=Q.front();Q.pop();
for(int i=head[x];~i;i=e[i].next)
{
int to=e[i].to;
if (d[x]+1<d[to]&&e[i^1].cap)
{
d[to]=d[x]+1;
Q.push(to);
}
}
}
}
int update(int x,int to)
{
int ret=INF;
for(int i=x;i!=to;i=e[pre[i]^1].to)
ret=min(ret,e[pre[i]].cap-e[pre[i]].flow);
for(int i=x;i!=to;i=e[pre[i]^1].to)
{
e[pre[i]].flow+=ret;
e[pre[i]^1].flow-=ret;
}
return ret;
}
int ISAP(int s,int t)
{
bfs(t);
for(int i=1;i<=n;i++) num[d[i]]++;
for(int i=1;i<=n;i++) cur[i]=head[i];
int ret=0,x=s;
while (d[s]<=n)
{
if (x==t) ret+=update(t,s),x=s;
int flag=0;
for(int i=cur[x];~i;i=e[i].next)
{
int to=e[i].to;
if (d[x]==d[to]+1&&e[i].flow<e[i].cap)
{
flag=1,cur[x]=i;
pre[x=to]=i;
break;
}
}
if (!flag)
{
int idx=n-1;
for(int i=head[x];~i;i=e[i].next)
if (e[i].flow<e[i].cap)
idx=min(idx,d[e[i].to]);
if (--num[d[x]]==0) break;
num[d[x]=idx+1]++;
cur[x]=head[x];
if (x!=s) x=e[pre[x]^1].to;
}
}
return ret;
}
int main()
{
n=read(),m=read();
st=read(),ed=read();
for(int i=1;i<=n;i++) head[i]=-1;
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
add(u,v,read());
add(v,u,0);
}
printf("%d",ISAP(st,ed));
return 0;
}

  • 最小费用最大流

Min_Cost_Max_Flow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include<cstdio>
#include<queue>
using namespace std;
const int M=50050,N=5050,INF=1<<25;
int n,m,st,ed,head[N],cnt=0,pre[N],d[N],c[N],cost=0,inq[N];
struct edge{int to,next,flow,cap,cost;} e[M<<1];
queue<int> Q;
inline int read()
{
register int x=0,t=1;
register char ch=getchar();
while (ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if (ch=='-') t=-1,ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
void add(int u,int v,int cap,int cost)
{
e[cnt].next=head[u];
head[u]=cnt;
e[cnt].to=v;
e[cnt].cost=cost;
e[cnt++].cap=cap;
}
void update(int x,int to,int flow)
{
for(int i=x;i!=to;i=e[pre[i]^1].to)
{
e[pre[i]].flow+=flow;
e[pre[i]^1].flow-=flow;
}
}
int SPFA(int s,int t)
{
for(int i=1;i<=n;i++) d[i]=INF,c[i]=0;
d[s]=0,c[s]=INF,Q.push(s);
while (!Q.empty())
{
int x=Q.front();
Q.pop(),inq[x]=0;
for(int i=head[x];~i;i=e[i].next)
{
int to=e[i].to,cost=e[i].cost;
if (e[i].flow<e[i].cap&&d[x]+cost<d[to])
{
d[to]=d[x]+cost;
pre[to]=i;
c[to]=min(c[x],e[i].cap-e[i].flow);
if (!inq[to]) Q.push(to),inq[to]=1;
}
}
}
return c[t];
}
int MCMF(int s,int t)
{
int ret=0,new_flow;
while (new_flow=SPFA(s,t))
{
ret+=new_flow;
cost+=new_flow*d[t];
update(t,s,new_flow);
}
return ret;
}
int main()
{
n=read(),m=read();
st=read(),ed=read();
for(int i=1;i<=n;i++) head[i]=-1;
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
int cap=read(),cost=read();
add(u,v,cap,cost);
add(v,u,0,-cost);
}
int max_flow=MCMF(st,ed);
printf("%d %d",max_flow,cost);
return 0;
}

洛谷P1108 低价购买

发表于 2018-07-13 | 分类于 OI
字数统计: 212 | 阅读时长 ≈ 1

dp 数组记录方案数,f 数组记录购买次数

同时去重

阅读全文 »

[TJOI2015]线性代数

发表于 2018-07-13 | 分类于 OI
字数统计: 705 | 阅读时长 ≈ 4

首先要看得懂题目
同时取A 中的i,j 两点可获得,但要减去
记为一条从u 到v 的,流量为cap 的,费用为cost 的弧与反弧
转化成最小割
对于B 中每个二元组,连边,和
i= j 的情况需要特殊处理
对于C 中的第k 个元素,连边

关于网络流,应该在这里就要暂告一段落了

阅读全文 »

洛谷P3355 骑士共存问题

发表于 2018-07-13 | 分类于 OI
字数统计: 598 | 阅读时长 ≈ 4

和上一题一样的套路
最多骑士数=总骑士数-最少拿走的骑士数
二染色之后构图

阅读全文 »

洛谷P2774 方格取数问题

发表于 2018-07-13 | 分类于 OI
字数统计: 643 | 阅读时长 ≈ 4

最大和=全局和-舍弃和,而舍弃和=最小割=最大流
记为一条从u 到v 的,流量为cap 的,费用为cost 的弧与反弧
将图二染色
对于每个黑点u ,连边
对于每个白点v ,连边
对于每个黑点u ,像周围白点v 连边

阅读全文 »

洛谷P4014 分配问题

发表于 2018-07-13 | 分类于 OI
字数统计: 702 | 阅读时长 ≈ 4

记为一条从u 到v 的,流量为cap 的,费用为cost 的弧与反弧
源点向每件工作连边
按惯例人当做两个用,第k 个人连边,
每件工作x 向第k 个人连边
跑一遍MCMF,边权取反再跑一遍

阅读全文 »

洛谷P1175 表达式的转换

发表于 2018-07-13 | 分类于 OI
字数统计: 362 | 阅读时长 ≈ 2

优化了一下之前的代码

阅读全文 »

洛谷P4015 运输问题

发表于 2018-07-10 | 分类于 OI
字数统计: 692 | 阅读时长 ≈ 4

记为一条从u 到v 的,流量为cap 的,费用为cost 的弧与反弧
对于每个仓库连边
对于每个零售店连边
仓库i 向零售店j 连边
跑一边S 到T 的MCMF,cost为最小运输费用
边权取负,再跑一边S 到T 的MCMF,-cost为最大运输费用

阅读全文 »

洛谷P4016 负载平衡问题

发表于 2018-07-10 | 分类于 OI
字数统计: 616 | 阅读时长 ≈ 4

这题的另一种做法(传送门)
记为一条从u 到v 的,流量为cap 的,费用为cost 的弧与反弧
记ave 为平均值
对于每个点x
若,则连边
若,则连边
每个点向左向右连边
跑一边MCMF,cost 就是最少搬运量

阅读全文 »

[HAOI2008]糖果传递

发表于 2018-07-10 | 分类于 OI
字数统计: 256 | 阅读时长 ≈ 1

环形均分纸牌
对于非环形均分纸牌,记为前i项的和,ave 为平均数
可得交换数量为

记为前i项,每项减去ave 的和
则交换数量为

对于环形均分纸牌,设在第k 个人处断开
则为

根据定义可得
总交换数量为

取中位数即可

阅读全文 »
1…8910…12
CWHer

CWHer

OIer/ACGN

120 日志
1 分类
58 标签
RSS
GitHub ZhiHu
Links
  • 洛谷
© 2018 | CWHer
本站访客数:
|
博客全站共54.4k字