网络流学习笔记
还在施工之中,先将就着看着吧
网络流中关于反向边的个人理解
建反向边的目的是,在你下一次找增广路的时候,沿着反向边走的流量就代表之前走这条路的那条增广路要回退多少,而这一次走的流量就顺着上一次的增广路把回退流量补上,而那些回退的流量就再去找别的路径
就像这样,路径2挤掉了路径1的2的流量,继续沿着路径1的线路走
而路径1被挤掉的流量就要回到上一个节点重新找路径
有点像反悔贪心
点击查看 网络流 EK算法 模板
#include<bits/stdc++.h>
using namespace std;
int n,m,s,t;//s为源点,t为汇点
struct edge
{
int f,t;
long long c;//流量上限
};
edge edges[100000];
int cnt=1;//存边数,初始为1是为了后续取反边
struct node
{
long long mf;//max_f 从 S 出发到这个点最大流量上限
vector<int> to;//存出边
int pre;//前驱边
};
node nodes[100000];
bool bfs()
{
for(int yy=1; yy<=n; yy++)
{
nodes[yy].mf=0;//清空流量数组
}
queue<int> q;//队列
q.push(s);//源点入队
nodes[s].mf=1e9;//标记源点的水流为无限大
while(!q.empty())
{
int now_=q.front();//现在在那个节点
q.pop();
int to,edg;
for(int k=0; k<nodes[now_].to.size(); k++)//遍历所有出边
{
edg=nodes[now_].to[k];//现在在哪条边
to=edges[edg].t;//去到哪个节点
if(nodes[to].mf==0&&edges[edg].c)//如果要去的节点没被去过并且这条边的流量不为 0
{
nodes[to].mf=min(nodes[now_].mf,edges[edg].c);//记录要去的节点的流量
nodes[to].pre=edg;//记录是从哪条边流过来的流量
q.push(to);//将要去的节点入队
if(to==t)//如果抵达汇点
{
return 1;
}
}
}
}
return 0;//到不了汇点
}
long long e_k()//EK 算法
{
long long tot_f=0;//总流量
while(bfs())//如果还有增广路
{
int now_=t;//现在在那个节点
while(now_!=s)//如果还没有回到原点
{
int edg=nodes[now_].pre;//这个节点的流量是从哪条边来的
edges[edg].c-=nodes[t].mf;//将正边剩余流量减去这一条增广路的流量
edges[edg^1].c+=nodes[t].mf;//将反向边加上这一条增广路的流量
now_=edges[edg^1].t;//继续向前
}
tot_f+=nodes[t].mf;//总流量加上这一条增广路的流量
}
return tot_f;
}
int main()
{
ios::sync_with_stdio(0);
cin>>n>>m>>s>>t;
long long a,b,c;
for(int ww=1; ww<=m; ww++)
{
cin>>a>>b>>c;
edges[++cnt].c=c;
edges[cnt].f=a;
edges[cnt].t=b;
nodes[a].to.push_back(cnt);
edges[++cnt].c=0;//建反向边,初始流量为零
edges[cnt].f=b;
edges[cnt].t=a;
nodes[b].to.push_back(cnt);
}
cout<<e_k();//跑EK算法
return 0;
}
点击查看 网络流 Dinic算法 板子
#include<bits/stdc++.h>
using namespace std;
struct edge
{
long long c;//每条边的剩余流量
int f,t;
};
edge edges[100000];
int cnt=1;//边数从1开始
struct node
{
long long mf;//最小的流量
int num;//
int cur;//当前弧优化
vector<int> to;
int d;//节点深度,层数
};
node nodes[100000];
int n,m,s,t;
inline bool bfs()//分层用的bfs
{
for(int ww=1; ww<=n; ww++)//将节点层数清空
{
nodes[ww].d=0;
}
queue<int> q;//队列
q.push(s);
nodes[s].d=1;
int to,now_,edg;
while(!q.empty())//队列不为空
{
now_=q.front();
q.pop();
for(int i=0; i<nodes[now_].to.size(); i++)
{
edg=nodes[now_].to[i];
to=edges[edg].t;
if(nodes[to].d==0&&edges[edg].c)
{
nodes[to].d=nodes[now_].d+1;
q.push(to);
if(to==t)
{
return 1;
}
}
}
}
return 0;
}
inline long long dfs(int now_,long long mf)
{
if(now_==t)//如果到了汇点
{
return mf;
}
long long sum=0;
int edg,to;
for(int i=nodes[now_].cur; i<nodes[now_].to.size(); i++)
{
edg=nodes[now_].to[i];//当前弧优化
nodes[now_].cur=i;
to=edges[edg].t;
if(nodes[to].d==nodes[now_].d+1&&edges[edg].c)//如果在下一层
{
long long f=dfs(to,min(mf,edges[edg].c));//算出流量
edges[edg].c-=f;
edges[edg^1].c+=f;
sum+=f;//
mf-=f;//将剩余流量减去这个流量
if(mf==0)//优化残量优化
{
break;
}
}
}
if(sum==0)//如果没有任何更多的流量
{
nodes[now_].d=0;//将这个节点删去
}
return sum;
}
long long dinic()
{
long long tot_f=0;
while(bfs())//如果还有增广路的话
{
for(int yy=1;yy<=n;yy++)
{
nodes[yy].cur=0;//将当前弧清空
}
tot_f+=dfs(s,1e9);//加上新流量
}
return tot_f;
}
int main()
{
ios::sync_with_stdio(0);
cin>>n>>m>>s>>t;
long long a,b,c;
for(int ee=1; ee<=m; ee++)
{
cin>>a>>b>>c;
edges[++cnt].f=a;
edges[cnt].t=b;
edges[cnt].c=c;
nodes[a].to.push_back(cnt);
edges[++cnt].f=b;
edges[cnt].t=a;
edges[cnt].c=0;
nodes[b].to.push_back(cnt);
}
cout<<dinic();
return 0;
}