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
样例说明:
题目中存在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=0;bool f=1; R char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return f?x:-x; } const int N=1e4+10; const int M=1e5+10; int n,m,S,T,head[N],cur[N],dis[N],q[N*2]; bool vis[N]; struct node{ int v,next,cap,flow; }e[M<<1];int tot=1; void add(int x,int y,int z){ e[++tot]=(node){y,head[x],z,0};head[x]=tot; e[++tot]=(node){x,head[y],0,0};head[y]=tot; } bool bfs(){ int h=0,t=1; memset(dis,-1,sizeof(dis)); dis[S]=0;q[1]=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]==-1&&e[i].cap>e[i].flow){//TLE*1 dis[v]=dis[x]+1; q[++t]=v; } } } return dis[T]!=-1; } int dfs(int x,int f){ if(x==T||!f) return f; int used=0,f1; for(int &i=cur[x];i;i=e[i].next){ if(dis[x]+1==dis[e[i].v]&&(f1=dfs(e[i].v,min(f,e[i].cap-e[i].flow)))>0){ e[i].flow+=f1;e[i^1].flow-=f1; used+=f1;f-=f1; if(!f) break; } } return used; } int dinic(){ int ans=0; while(bfs()){ for(int i=1;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=1,x,y,z;i<=m;i++){ x=read();y=read();z=read(); add(x,y,z); } printf("%d",dinic()); return 0; }
Dinic 2
#include<cstdio> #include<cstring> #include<queue> #define R register #define inf 0x3f3f3f3f using namespace std; int read(){ R int x=0;bool f=1; R char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return f?x:-x; } const int N=1e5+10; int S,T,n,m; int head[N],dis[N],q[N*2]; struct node{ int v,next,cap; }e[N<<2];int tot=1; void add(int x,int y,int z){ e[++tot]=(node){y,head[x],z};head[x]=tot; } bool bfs(){ int h=0,t=1; memset(dis,-1,sizeof(dis)); dis[S]=0;q[1]=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]==-1&&e[i].cap){ dis[v]=dis[x]+1; q[++t]=v; } } } return dis[T]!=-1; } 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]+1&&rest){ int t=dfs(v,min(rest,e[i].cap)); if(!t) dis[v]=0; e[i].cap-=t; e[i^1].cap+=t; rest-=t; } } return f-rest; } int dinic(){ int ans=0; while(bfs()) ans+=dfs(S,inf); return ans; } int main(){ scanf("%d%d%d%d",&n,&m,&S,&T); for(int i=1,x,y,z;i<=m;i++){ scanf("%d%d%d",&x,&y,&z); add(x,y,z);add(y,x,0); } printf("%d",dinic()); return 0; }
ISAP
#include<cstdio> #include<cstring> #include<queue> #define R register using namespace std; int read(){ R int x=0;bool f=1; R char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return f?x:-x; } const int N=1e4+10; const int M=1e5+10; 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=0,int v=0,int next=0,int cap=0,int flow=0){ this->u=u; this->v=v; this->next=next; this->cap=cap; this->flow=flow; } }e[M<<1];int tot=1; void add(int x,int y,int z){ e[++tot]=node(x,y,head[x],z,0); head[x]=tot; } void bfs(){ queue<int>q; q.push(T); vis[T]=1;dis[T]=0; 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]=1; dis[v]=dis[x]+1; 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]^1].flow-=ans; return ans; } int ISAP(){ int ans=0; for(int i=1;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=0; for(int i=cur[p];i;i=e[i].next){ int v=e[i].v;//寻找当前找到的一条路径上的最大流 if(dis[p]==dis[v]+1&&e[i].cap>e[i].flow){ ok=1;par[v]=i;cur[p]=i;p=v; break; } } if(!ok){//找不到可行弧 if(--gap[dis[p]]==0) break;//(更新gap数组)当前标号的数目减1 =>如果出现断层,则该点为一个唯一点,后退也没有意义 int mn=n-1;//寻找与当前点相连接的点中最小的距离标号 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+1]++; 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=1,x,y,z;i<=m;i++){ x=read();y=read();z=read(); add(x,y,z); add(y,x,0); } bfs(); printf("%d",ISAP()); return 0; }