@Yeasion-Nein
2018-07-30T20:03:58.000000Z
字数 12294
阅读 1353
网络流
1:算法 ()
而当找不到增广路的时候,当前的流就是最大流了。
-=; +=;
#define MAXN 100010
#define INF 0x7fffffff
bool visit[MAXN];
int pre[MAXN];
queue<int> q;
void update(int now,int rest){
while(pre[now]){
map[pre[now]][now]-=rest;//正向的-=rest
map[now][pre[now]]+=rest;//负向的+=rest
now=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]);//最小的rest
pre[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 0x7fffffff
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 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并且这个点还没有被发放deep
deep[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不为0
int 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 0x7fffffff
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并且这个点还没有被发放deep
deep[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不为0
int 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 0x7fffffff
using 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并且这个点还没有被发放deep
deep[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不为0
int 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 qwq
q.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的前驱为now
rest[edge[i].to]=min(rest[now],edge[i].cap);
//寻找最小的流量
if(!inque[edge[i].to]){//入队,继续SPFA
q.push(edge[i].to);
inque[edge[i].to]=1;
}
}
}
if(pre[end]==-1) return 0;
//如果没有找到t即:t的前驱依然是不存在的-1,则没有增广路,返回0,停止EK
else return 1; //继续进行EK
}
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define MAXN 100010
#define INF 0x7fffffff
#define ll long long
using 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;
}