网络流、费用流、二分图学习笔记
未完待续
网络流
%%%%强推%%%%
这篇思路不错:https://www.cnblogs.com/ZJUT-jiangnan/p/3632525.html
洛谷日报也还行:https://www.luogu.com.cn/blog/ONE-PIECE/wang-lao-liu-di-zong-jie
这篇dinic强力推荐:https://www.cnblogs.com/DavidJing/p/10713197.html
现在终于知道为什么这么多人用“memset(head,-1)”了
这样tot初始值为-1,第一条边的编号就为0了,用“^i”就可以求出“i”的反向边了
代码:
#include<bits/stdc++.h>
#define ll long long
#define N 110000
using namespace std;
ll n,m,s,t,x,y,z,tot=1,head[N],hd[N],dep[N],inf=0x7fffffff;
struct node{
ll to,dis,nxt;
}e[5*N];
void add(ll f,ll to,ll dis){
e[++tot].to=to;
e[tot].dis=dis;
e[tot].nxt=head[f];
head[f]=tot;
}
ll bfs(){
memcpy(hd,head,sizeof(hd));
memset(dep,0,sizeof(dep));
queue<ll>q;
dep[s]=1;
q.push(s);
while(!q.empty()){
ll u=q.front();
q.pop();
for(ll i=head[u];i;i=e[i].nxt){
ll v=e[i].to;
if(!dep[v]&&e[i].dis>0){
dep[v]=dep[u]+1;
q.push(v);
}
}
}
return dep[t];
}
ll dfs(ll u,ll lim){
if(u==t||!lim)return lim;
ll flow=0;
for(ll i=hd[u];i&&lim;i=e[i].nxt){
hd[u]=i;
ll v=e[i].to,ff;
if(dep[v]==dep[u]+1&&(ff=dfs(v,min(lim,e[i].dis)))){
lim-=ff;
e[i].dis-=ff;
e[i^1].dis+=ff;
flow+=ff;
}
}
return flow;
}
ll dinic(){
ll sum=0;
while(bfs())sum+=dfs(s,inf);
return sum;
}
int main(){
scanf("%lld%lld%lld%lld",&n,&m,&s,&t);
for(ll i=1;i<=m;i++){
scanf("%lld%lld%lld",&x,&y,&z);
add(x,y,z);
add(y,x,0);
}
printf("%lld",dinic());
}
二分图
这篇匈牙利强力推荐:https://blog.csdn.net/u013384984/article/details/90718287
其实二分图匹配还可以用网络流dinic实现
设置一个超级点源S,一个超级点束T
S连向所有左边点,所有右边点连向T,再跑S到T的最大流即可
代码:(匈牙利算法)
#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int n,m,e,u,v,ans,match[N];
bool a[N][N],vis[N];
bool dfs(int x) {
for(int i=1;i<=m;i++)if(!vis[i]&&a[x][i]){
vis[i]=1;
if(!match[i]||dfs(match[i])){
match[i]=x;
return 1;
}
}
return 0;
}
int main() {
scanf("%d %d %d",&n,&m,&e);
for(int i=1;i<=e;i++)scanf("%d %d",&u,&v),a[u][v]=1;
for (int i=1; i<=n;i++){
ans+=dfs(i);
memset(vis,0,sizeof(vis));
}
printf("%d",ans);
}
(dinic)
#include<bits/stdc++.h>
#define ll long long
#define N 110000
using namespace std;
ll n,m,x,y,z,tot=1,s,t,head[N],dep[N],hd[N],inf=0x7fffffff;
struct node{
ll to,dis,nxt;
}e[5*N];
void add(ll f,ll to,ll dis){
e[++tot].to=to;
e[tot].dis=dis;
e[tot].nxt=head[f];
head[f]=tot;
}
ll bfs(){
memcpy(hd,head,sizeof(hd));
memset(dep,0,sizeof(dep));
queue<ll>q;
dep[s]=1;
q.push(s);
while(!q.empty()){
ll u=q.front();
q.pop();
for(ll i=head[u];i;i=e[i].nxt){
ll v=e[i].to;
if(!dep[v]&&e[i].dis>0){
dep[v]=dep[u]+1;
q.push(v);
}
}
}
return dep[t];
}
ll dfs(ll u,ll lim){
if(!lim||u==t)return lim;
ll flow=0;
for(ll i=hd[u];i&&lim;i=e[i].nxt){
hd[u]=i;
ll v=e[i].to,ff=0;
if(dep[v]==dep[u]+1&&(ff=dfs(v,min(lim,e[i].dis)))){
lim-=ff;
e[i].dis-=ff;
e[i^1].dis+=ff;
flow+=ff;
}
}
return flow;
}
ll dinic(){
ll ans=0;
while(bfs())ans+=dfs(s,inf);
return ans;
}
int main(){
scanf("%lld%lld",&n,&m);
s=m+1,t=m+2;
while(1){
scanf("%lld%lld",&x,&y);
if(x==-1&&y==-1)break;
add(x,y,inf);
add(y,x,0);
}
for(ll i=1;i<=n;i++){
add(s,i,1);
add(i,s,0);
}
for(ll i=n+1;i<=m;i++){
add(i,t,1);
add(t,i,0);
}
ll ans=dinic();
if(!ans){puts("No Solution!");return 0;}
printf("%lld\n",ans);
for(ll i=2;i<=tot;i+=2)if(e[i].to!=s&&e[i].to!=t&&e[i^1].to!=s&&e[i^1].to!=t&&e[i^1].dis!=0){
printf("%lld %lld\n",e[i^1].to,e[i].to);//然而还可以这样输出匹配结果
}
}
费用流
把EK里的bfs换成spfa即可
代码:
#include<bits/stdc++.h>
#define ll long long
#define N 110000
using namespace std;
ll n,m,s,t,x,y,z,w,tot=1,mxf,mnc,head[N],hd[N],dis[N],flow[N],pre[N],last[N],inf=0x7fffffff;
bool vis[N];
struct node{
ll f,to,dis,nxt;
}e[5*N];
void add(ll f,ll to,ll fl,ll dis){
e[++tot].to=to;
e[tot].dis=dis;
e[tot].nxt=head[f];
e[tot].f=fl;
head[f]=tot;
}
bool spfa(){
memset(dis,0x7f,sizeof(dis));
memset(flow,0x7f,sizeof(flow));
memset(vis,0,sizeof(vis));
queue<ll>q;
vis[s]=1;dis[s]=0;pre[t]=0;
q.push(s);
while(!q.empty()){
ll u=q.front();
q.pop();
for(ll i=head[u];i;i=e[i].nxt){
ll v=e[i].to;
if(dis[v]>dis[u]+e[i].dis&&e[i].f>0){
dis[v]=dis[u]+e[i].dis;
pre[v]=u;
last[v]=i;
flow[v]=min(flow[u],e[i].f);
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
vis[u]=0;
}
return pre[t];
}
void dinic(){
while(spfa()){
ll u=t;
mxf+=flow[t];
mnc+=flow[t]*dis[t];
while(u!=s){
e[last[u]].f-=flow[t];
e[last[u]^1].f+=flow[t];
u=pre[u];
}
}
}
int main(){
scanf("%lld%lld%lld%lld",&n,&m,&s,&t);
for(ll i=1;i<=m;i++){
scanf("%lld%lld%lld%lld",&x,&y,&z,&w);
add(x,y,z,w),add(y,x,0,-w);
}
dinic();
printf("%lld %lld",mxf,mnc);
}