P3376 【模板】网络最大流

时间:2023-03-09 07:41:08
P3376 【模板】网络最大流

P3376 【模板】网络最大流

题目描述

如题,给出一个网络图,以及其源点和汇点,求出其网络最大流。

输入输出格式

输入格式:

第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。

接下来M行每行包含三个正整数ui、vi、wi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi)

输出格式:

一行,包含一个正整数,即为该网络的最大流。

输入输出样例

输入样例#1:
4 5 4 3
4 2 30
4 3 20
2 3 20
2 1 30
1 3 40
输出样例#1:
50

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=10,M<=25

对于70%的数据:N<=200,M<=1000

对于100%的数据:N<=10000,M<=100000

样例说明:

P3376 【模板】网络最大流

题目中存在3条路径:

4-->2-->3,该路线可通过20的流量

4-->3,可通过20的流量

4-->2-->1-->3,可通过10的流量(边4-->2之前已经耗费了20的流量)

故流量总计20+20+10=50。输出50。

Dinic1

#include<cstdio>
#include<cstring>
#include<queue>
#define R register
using namespace std;
int read(){
R int x=;bool f=;
R char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return f?x:-x;
}
const int N=1e4+;
const int M=1e5+;
int n,m,S,T,head[N],cur[N],dis[N],q[N*];
bool vis[N];
struct node{
int v,next,cap,flow;
}e[M<<];int tot=;
void add(int x,int y,int z){
e[++tot]=(node){y,head[x],z,};head[x]=tot;
e[++tot]=(node){x,head[y],,};head[y]=tot;
}
bool bfs(){
int h=,t=;
memset(dis,-,sizeof(dis));
dis[S]=;q[]=S;
while(h!=t){
int x=q[++h];
for(int i=head[x];i;i=e[i].next){
int v=e[i].v;
if(dis[v]==-&&e[i].cap>e[i].flow){//TLE*1
dis[v]=dis[x]+;
q[++t]=v;
}
}
}
return dis[T]!=-;
}
int dfs(int x,int f){
if(x==T||!f) return f;
int used=,f1;
for(int &i=cur[x];i;i=e[i].next){
if(dis[x]+==dis[e[i].v]&&(f1=dfs(e[i].v,min(f,e[i].cap-e[i].flow)))>){
e[i].flow+=f1;e[i^].flow-=f1;
used+=f1;f-=f1;
if(!f) break;
}
}
return used;
}
int dinic(){
int ans=;
while(bfs()){
for(int i=;i<=n;i++) cur[i]=head[i];
ans+=dfs(S,0x7fffffff);
}
return ans;
}
int main(){
n=read();m=read();S=read();T=read();
for(int i=,x,y,z;i<=m;i++){
x=read();y=read();z=read();
add(x,y,z);
}
printf("%d",dinic());
return ;
}

Dinic 2

#include<cstdio>
#include<cstring>
#include<queue>
#define R register
#define inf 0x3f3f3f3f
using namespace std;
int read(){
R int x=;bool f=;
R char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return f?x:-x;
}
const int N=1e5+;
int S,T,n,m;
int head[N],dis[N],q[N*];
struct node{
int v,next,cap;
}e[N<<];int tot=;
void add(int x,int y,int z){
e[++tot]=(node){y,head[x],z};head[x]=tot;
}
bool bfs(){
int h=,t=;
memset(dis,-,sizeof(dis));
dis[S]=;q[]=S;
while(h!=t){
int x=q[++h];
for(int i=head[x];i;i=e[i].next){
int v=e[i].v;
if(dis[v]==-&&e[i].cap){
dis[v]=dis[x]+;
q[++t]=v;
}
}
}
return dis[T]!=-;
}
int dfs(int now,int f){
if(now==T) return f;
int rest=f;
for(int i=head[now];i;i=e[i].next){
int v=e[i].v;
if(e[i].cap&&dis[v]==dis[now]+&&rest){
int t=dfs(v,min(rest,e[i].cap));
if(!t) dis[v]=;
e[i].cap-=t;
e[i^].cap+=t;
rest-=t;
}
}
return f-rest;
}
int dinic(){
int ans=;
while(bfs()) ans+=dfs(S,inf);
return ans;
}
int main(){
scanf("%d%d%d%d",&n,&m,&S,&T);
for(int i=,x,y,z;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);add(y,x,);
}
printf("%d",dinic());
return ;
}

ISAP

#include<cstdio>
#include<cstring>
#include<queue>
#define R register
using namespace std;
int read(){
R int x=;bool f=;
R char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return f?x:-x;
}
const int N=1e4+;
const int M=1e5+;
int n,m,S,T,head[N],cur[N],par[N],gap[N],dis[N];
bool vis[N];
struct node{
int u,v,next,cap,flow;
node(int u=,int v=,int next=,int cap=,int flow=){
this->u=u;
this->v=v;
this->next=next;
this->cap=cap;
this->flow=flow;
}
}e[M<<];int tot=;
void add(int x,int y,int z){
e[++tot]=node(x,y,head[x],z,);
head[x]=tot;
}
void bfs(){
queue<int>q;
q.push(T);
vis[T]=;dis[T]=;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x];i;i=e[i].next){
int v=e[i].v;
if(!vis[v]&&!e[i].cap){
vis[v]=;
dis[v]=dis[x]+;
q.push(v);
}
}
}
}
int agument(){//更新残留网络
int ans=0x7fffffff;
for(int p=T;p!=S;p=e[par[p]].u) ans=min(ans,e[par[p]].cap-e[par[p]].flow);
for(int p=T;p!=S;p=e[par[p]].u) e[par[p]].flow+=ans,e[par[p]^].flow-=ans;
return ans;
}
int ISAP(){
int ans=;
for(int i=;i<=n;i++) gap[dis[i]]++,cur[i]=head[i];
for(int p=S;dis[p]<n;){
if(p==T){//达到终点就增广
ans+=agument();
p=S;
}
bool ok=;
for(int i=cur[p];i;i=e[i].next){
int v=e[i].v;//寻找当前找到的一条路径上的最大流
if(dis[p]==dis[v]+&&e[i].cap>e[i].flow){
ok=;par[v]=i;cur[p]=i;p=v;
break;
}
}
if(!ok){//找不到可行弧
if(--gap[dis[p]]==) break;//(更新gap数组)当前标号的数目减1 =>如果出现断层,则该点为一个唯一点,后退也没有意义
int mn=n-;//寻找与当前点相连接的点中最小的距离标号
for(int i=head[p];i;i=e[i].next) if(e[i].cap>e[i].flow) mn=min(mn,dis[e[i].v]);
gap[dis[p]=mn+]++;
cur[p]=head[p];
if(p!=S) p=e[par[p]].u;//相当于后退一步
}
}
return ans;
}
int main(){//初始化清零已省去
n=read();m=read();S=read();T=read();
for(int i=,x,y,z;i<=m;i++){
x=read();y=read();z=read();
add(x,y,z);
add(y,x,);
}
bfs();
printf("%d",ISAP());
return ;
}