网络流是一种类比水流的解决问题的方法,首先我们要明白它解决的是什么样的问题。
比如说最基本的,从水厂通过各种水管到达你家的能有多少水量,每个水管有自己的流量限制,也就是说最多留这么多水。
从1到达3,结果为3。水可以走许多条路,但是最终还是不会大于2到3管道的1,4到3管道的2流量。
在这里只介绍简单的EK算法,解决一般的网络流问题足够用,dinic算法明白其中的含义会用就行,不需要深究。
/*
1.网络流算法用来一个网络中的最大流量,每个水管都有自己的某个限制。
2.其实简单的ek算法就是通过不断寻找增广路,找到增广路中的最小权值然后减去它。
3.记录了前驱,然后倒着走一遍,将所有网络中的边减去这个最小值,再次寻找增广路。
4.增广路其实找一条能到的路就行。
5.这个EK算法可以寻找,复杂度o(v*e*e)。DINIC算法又加上了个dfs,复杂度有所减少。
我的网络流模板出了点问题,这里借用了大佬的模板,看起来比较详细(orz)。
*/
/*测试样例
5 4
1 2 5
1 4 5
2 3 1
4 3 2
2 4 3
*/
#include
using namespace std;
const int maxn=205;
const int inf=0x7fffffff;
int r[maxn][maxn]; //残留网络,初始化为原图
bool visit[maxn];
int pre[maxn];
int m,n;
bool bfs(int s,int t){
//寻找一条从s到t的增广路,若找到返回true,所谓增广路其实就是找s到t的一条路,能找到就行,并记录前驱。
int p;
queue q;
memset(pre,-1,sizeof(pre));
memset(visit,false,sizeof(visit));
pre[s]=s; visit[s]=true; q.push(s);
//从s到t
while(!q.empty()){ /这里用临界矩阵存储边,更好的可以用前向星。
//该过程其实就是爆搜。
p=q.front();
q.pop();
for(int i=1;i<=n;i++){
if(r[p][i]>0&&!visit[i]){
pre[i]=p; //前驱.*划重点啦
visit[i]=true;
if(i==t) return true; //能到终点
q.push(i);
}
}
}
return false;
}
int EdmondsKarp(int s,int t){
int flow=0,d,i;
/*
它的思想,如果有增广路(能到的路),因为我记录了前驱所以我可以对这条路
倒着走一遍,找到这些边权值最小的那个,然后然所有边的流量减去这个最小值
就行。这样就保证了所有流量
*/
while(bfs(s,t)){
d=inf;
for(i=t;i!=s;i=pre[i]) d=d
对上数样例输出为:3 结果显然。
学习网络流需要掌握EK算法的经典思想,dinic算法只给出模板,理解其中含义即可。
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAX 10100
#define MAXL 210000
#define rg register
#define INF 1000000000
inline int read() //读入优化
{
rg int x=0,t=1;rg char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-'){t=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*t;
}
int N,M,S,T,Ans=0;
bool vis[MAX];
struct Line
{
int v,next,w,fb;
}e[MAXL];
int h[MAX],cnt=1;
int level[MAX];
inline void Add(rg int u,rg int v,rg int w)
{
e[cnt]=(Line){v,h[u],w,cnt+1};
h[u]=cnt++;
e[cnt]=(Line){u,h[v],0,cnt-1};//存反边
h[v]=cnt++;
}
inline bool BFS()//分层
{
for(int i=1;i<=N;++i)level[i]=0;
level[S]=1;
queue Q;
while(!Q.empty())Q.pop();
Q.push(S);
while(!Q.empty())
{
int u=Q.front();Q.pop();
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;
if(e[i].w&&!level[v])//可以增广
{
level[v]=level[u]+1;
Q.push(v);
}
}
}
return level[T];//返回是否存在增广路
}
int DFS(rg int u,rg int t,rg int f)//从u到t,当前流量f
{
if(u==t||f==0)return f;//到达终点或者已经无法增广了
int re=0;//返回值
for(int i=h[u];i;i=e[i].next)//访问所有边
{
rg int v=e[i].v,d;
if(e[i].w&&level[v]==level[u]+1)//可以增广,并且满足分层图的要求
{
d=DFS(v,T,min(f,e[i].w));
re+=d;
f-=d;
e[i].w-=d;//更新流量
e[e[i].fb].w+=d;//反边
}
}
return re;
}
inline int Dinic()
{
int re=0;
while(BFS())re+=DFS(S,T,INF);
return re;
}
int main()
{
N=read();M=read();S=read();T=read();
for(rg int i=1;i<=M;++i)
{
rg int u=read(),v=read(),w=read();
Add(u,v,w);
}
rg int Ans=Dinic();
printf("%d\n",Ans);
return 0;
}
***五一快乐 想看老师女装 ***