@Yeasion-Nein
2018-07-30T12:03:58.000000Z
字数 12294
阅读 1524
网络流
1:算法 ()
而当找不到增广路的时候,当前的流就是最大流了。



-=; +=;
#define MAXN 100010#define INF 0x7fffffffbool visit[MAXN];int pre[MAXN];queue<int> q;void update(int now,int rest){while(pre[now]){map[pre[now]][now]-=rest;//正向的-=restmap[now][pre[now]]+=rest;//负向的+=restnow=pre[now];}}int find(int S,int T){//寻找增广路流量memset(visit,0,sizeof(visit));memset(pre,-1,sizeof(pre));visit[S]=1; int minn=INF;q.push(S);while(!q.empty()){int now=q.front(); q.pop();if(now==t) break;for(int i=1;i<=m;i++){if(!visit[i]&&MAP[now][i]){q.push(i);minn=min(minn,map[now][i]);//最小的restpre[i]=now; visit[i]=1;}}}if(pre[i]==-1) return 0;return minn;}int EK(int S,int T){ //EK算法主体int new_flow=0;//增广路的流量int max_flow=0;//最大流do{new_flow=find(S,T);update(T,new_flow);max_flow+=new_flow;}while(new_flow);return max_flow;}
算法
#define MAXN 100010#define INF 0x7fffffffint n,m,s,t;//n:点数,m:边数,s:源点,t:汇点struct node{//前向星不解释int from;int to;int next;int rest;//每一条边的剩余流量}edge[MAXN*100];int head[MAXN],total=-1;void add(int f,int t,int l){total++;edge[total].from=f;edge[total].to=t;edge[total].rest=l;edge[total].next=head[f];head[f]=total;}int deep[MAXN];//深度queue<int> q;//BFS用队列bool bfs(){//bfs用来寻找分层图,增广路while(!q.empty()) q.pop();//清空队列memset(deep,0,sizeof(deep));//清空深度deep[s]=1; q.push(s);//处理源点do{int now=q.front(); q.pop();//取队首for(int i=head[now];i!=-1;i=edge[i].next){if(edge[i].rest&&!deep[edge[i].to]){//如果这条边还有rest并且这个点还没有被发放deepdeep[edge[i].to]=deep[now]+1;q.push(edge[i].to);//入队列接着bfs}}}while(!q.empty());if(deep[t]==0) return 0;//当没有汇点的深度时,说明不存在分层图,也就没有增广路else return 1; //有增广路,可以跑Dinic。}int dfs(int now,int flow){//now:当前节点,flow:当前流量if(now==t||!flow) return flow;int res=0;for(int i=head[now];i!=-1;i=edge[i].next){if(deep[edge[i].to]==deep[now]+1&&edge[i].rest){//如果满足分层图并且rest不为0int rest=dfs(edge[i].to,min(flow,edge[i].rest));//接着向下dfs。if(rest>0){//增广成功edge[i].rest-=rest;//正向边减去剩余流量edge[i^1].rest+=rest;//负向边加上剩余流量res+=rest;flow-=rest;}}}return res;//没有增广路的话,就返回0.}int Dinic(){int ans=0; //用来记录最大流量while(bfs()){while(int d=dfs(s,INF))ans+=d;}return ans;}
#define MAXN 100010#define INF 0x7fffffffint n,m,s,t;//n:点数,m:边数,s:源点,t:汇点struct node{//前向星不解释int from;int to;int next;int rest;//每一条边的剩余流量}edge[MAXN*100];int head[MAXN],total=-1;void add(int f,int t,int l){total++;edge[total].from=f;edge[total].to=t;edge[total].rest=l;edge[total].next=head[f];head[f]=total;}int cur[MAXN];//这就是那个cur,用来当前弧优化int deep[MAXN];//深度queue<int> q;//BFS用队列bool bfs(){//bfs用来寻找分层图,增广路while(!q.empty()) q.pop();//清空队列memset(deep,0,sizeof(deep));//清空深度deep[s]=1; q.push(s);//处理源点do{int now=q.front(); q.pop();//取队首for(int i=head[now];i!=-1;i=edge[i].next){if(edge[i].rest&&!deep[edge[i].to]){//如果这条边还有rest并且这个点还没有被发放deepdeep[edge[i].to]=deep[now]+1;q.push(edge[i].to);//入队列接着bfs}}}while(!q.empty());if(deep[t]==0) return 0;//当没有汇点的深度时,说明不存在分层图,也就没有增广路else return 1; //有增广路,可以跑Dinic。}int dfs(int now,int flow){//now:当前节点,flow:当前流量if(now==t||!flow) return flow;int res=0;for(int& i=cur[now];i!=-1;i=edge[i].next){//这就是当前弧优化的主要部分,前面的&是为了让cur和i一起变化if(deep[edge[i].to]==deep[now]+1&&edge[i].rest){//如果满足分层图并且rest不为0int rest=dfs(edge[i].to,min(flow,edge[i].rest));//接着向下dfs。if(rest>0){//增广成功edge[i].rest-=rest;//正向边减去剩余流量edge[i^1].rest+=rest;//负向边加上剩余流量res+=rest;flow-=rest;}}}return res;//没有增广路的话,就返回0.}int Dinic(){int ans=0; //用来记录最大流量while(bfs()){for(int i=1;i<=n;i++)cur[i]=head[i];//不要忘了重置while(int d=dfs(s,INF))ans+=d;}return ans;}
最大流模板题
输入样例#1:
4 5 4 3
4 2 30
4 3 20
2 3 20
2 1 30
1 3 40
输出样例#1:
50

#include<iostream>#include<cstdio>#include<queue>#include<cstring>#include<algorithm>#define MAXN 100010#define INF 0x7fffffffusing namespace std;int n,m,s,t;//n:点数,m:边数,s:源点,t:汇点struct node{//前向星不解释int from;int to;int next;int rest;//每一条边的剩余流量}edge[MAXN*100];int head[MAXN],total=-1;void add(int f,int t,int l){total++;edge[total].from=f;edge[total].to=t;edge[total].rest=l;edge[total].next=head[f];head[f]=total;}int cur[MAXN];//这就是那个cur,用来当前弧优化int deep[MAXN];//深度queue<int> q;//BFS用队列bool bfs(){//bfs用来寻找分层图,增广路while(!q.empty()) q.pop();//清空队列memset(deep,0,sizeof(deep));//清空深度deep[s]=1; q.push(s);//处理源点do{int now=q.front(); q.pop();//取队首for(int i=head[now];i!=-1;i=edge[i].next){if(edge[i].rest&&!deep[edge[i].to]){//如果这条边还有rest并且这个点还没有被发放deepdeep[edge[i].to]=deep[now]+1;q.push(edge[i].to);//入队列接着bfs}}}while(!q.empty());if(deep[t]==0) return 0;//当没有汇点的深度时,说明不存在分层图,也就没有增广路else return 1; //有增广路,可以跑Dinic。}int dfs(int now,int flow){//now:当前节点,flow:当前流量if(now==t||!flow) return flow;int res=0;for(int& i=cur[now];i!=-1;i=edge[i].next){//这就是当前弧优化的主要部分,前面的&是为了让cur和i一起变化if(deep[edge[i].to]==deep[now]+1&&edge[i].rest){//如果满足分层图并且rest不为0int rest=dfs(edge[i].to,min(flow,edge[i].rest));//接着向下dfs。if(rest>0){//增广成功edge[i].rest-=rest;//正向边减去剩余流量edge[i^1].rest+=rest;//负向边加上剩余流量res+=rest;flow-=rest;}}}return res;//没有增广路的话,就返回0.}int Dinic(){int ans=0; //用来记录最大流量while(bfs()){for(int i=1;i<=n;i++)cur[i]=head[i];//不要忘了重置while(int d=dfs(s,INF))ans+=d;}return ans;}int main(){scanf("%d%d%d%d",&n,&m,&s,&t);for(int i=1;i<=n;i++) head[i]=-1;for(int i=1;i<=m;i++){int x,y,l;scanf("%d%d%d",&x,&y,&l);add(x,y,l);add(y,x,0);}printf("%d",Dinic());return 0;}
int n,m,s,t;//n:点数,m:边数,s:起点,t:终点int dist[MAXN],flow[MAXN];//dist[i]:从s到i的最短路径长度(SPFA用)//flow:流量bool inque[MAXN];;//inque[i]表示点i是否在队列里面。int pre[MAXN],rest[MAXN];//pre[i]:i的前驱节点//rest[i]第i条边的剩余流量int max_flow; int min_spent;//max_flow:最大流//min_spent:最小花费queue<int> q;//队列
struct node{int from;int to;int len;//费用int cap;//流量int next;}edge[MAXN];int head[MAXN],total=-1;//要注意将这里的head[MAXN]和total都置为-1!Yeasion在这上面摔了好几次void add(int f,int t,int l,int c){total++;edge[total].from=f;edge[total].to=t;edge[total].len=l;edge[total].cap=c;edge[total].next=head[f];head[f]=total;}
int main(){scanf("%d%d%d%d",&n,&m,&s,&t);for(int i=1;i<=n;i++) head[i]=-1;for(int i=1;i<=m;i++){int x; int y; int l; int c;scanf("%d%d%d%d",&x,&y,&c,&l);add(x,y,l,c); add(y,x,0,-c);//注意加反向边要注意的两点哦} Edmonds_Karp(s,t);printf("%d %d",max_flow,min_spent);return 0;}
void Edmonds_Karp(int begin,int end){while(SPFA(begin,end)){//寻找增广路int now=end;max_flow+=rest[end];//将最大流加上最小流量min_spent+=dist[end]*rest[end];//将最小花费加上从s开始到t的最小路径长*到t的最小流量while(now!=begin){edge[last[now]].cap-=rest[end];//正向边减去最小流量edge[last[now]^1].cap+=rest[end];//反向边加上最小流量now=pre[now];//设置前趋}}}
bool SPFA(int begin,int end){while(!q.empty()) q.pop();memset(dist,127,sizeof(dist));memset(inque,0,sizeof(inque));memset(rest,127,sizeof(rest));//每一次的SPFA不要忘了将所有的变量还原//但千万别还原pre qwqq.push(begin); inque[begin]=1;//入队s点 ,初始化pre[end]=-1; dist[begin]=0;//SPFA过程while(!q.empty()){int now=q.front();q.pop();inque[now]=false;for(int i=head[now];i!=-1;i=edge[i].next)if(edge[i].cap>0)//这里就是网络流的部分了,首先这条边如果没有了残余流量我们肯定不跑if(dist[edge[i].to]>dist[now]+edge[i].len){dist[edge[i].to]=dist[now]+edge[i].len;//SPFA松弛操作pre[edge[i].to]=now;//更新edge[i].to的前驱为nowrest[edge[i].to]=min(rest[now],edge[i].cap);//寻找最小的流量if(!inque[edge[i].to]){//入队,继续SPFAq.push(edge[i].to);inque[edge[i].to]=1;}}}if(pre[end]==-1) return 0;//如果没有找到t即:t的前驱依然是不存在的-1,则没有增广路,返回0,停止EKelse return 1; //继续进行EK}
#include<iostream>#include<cstdio>#include<queue>#include<cstring>#include<algorithm>#define MAXN 100010#define INF 0x7fffffff#define ll long longusing namespace std;int n,m,s,t;struct node{int from;int to;int len;int cap;int next;}edge[MAXN];int head[MAXN],total=-1;void add(int f,int t,int l,int c){total++;edge[total].from=f;edge[total].to=t;edge[total].len=l;edge[total].cap=c;edge[total].next=head[f];head[f]=total;}int dist[MAXN],flow[MAXN];bool inque[MAXN]; int last[MAXN];int pre[MAXN],rest[MAXN];int max_flow; int min_spent;queue<int> q;bool SPFA(int begin,int end){while(!q.empty()) q.pop();memset(dist,127,sizeof(dist));memset(inque,0,sizeof(inque));memset(rest,127,sizeof(rest));q.push(begin); inque[begin]=1;pre[end]=-1; dist[begin]=0;while(!q.empty()){int now=q.front();q.pop();inque[now]=false;for(int i=head[now];i!=-1;i=edge[i].next)if(edge[i].cap>0)if(dist[edge[i].to]>dist[now]+edge[i].len){dist[edge[i].to]=dist[now]+edge[i].len;pre[edge[i].to]=now;last[edge[i].to]=i;rest[edge[i].to]=min(rest[now],edge[i].cap);if(!inque[edge[i].to]){q.push(edge[i].to);inque[edge[i].to]=1;}}}if(pre[end]==-1) return 0;else return 1;}void Edmonds_Karp(int begin,int end){while(SPFA(begin,end)){int now=end;max_flow+=rest[end];min_spent+=dist[end]*rest[end];while(now!=begin){edge[last[now]].cap-=rest[end];edge[last[now]^1].cap+=rest[end];now=pre[now];}}}int main(){scanf("%d%d%d%d",&n,&m,&s,&t);for(int i=1;i<=n;i++) head[i]=-1;for(int i=1;i<=m;i++){int x; int y; int l; int c;scanf("%d%d%d%d",&x,&y,&c,&l);add(x,y,l,c); add(y,x,0,-c);} Edmonds_Karp(s,t);printf("%d %d",max_flow,min_spent);return 0;}