题目
https://www.luogu.org/problemnew/show/P3376
解题思路
【{什么是Dinic算法}引:1、每次以源点为起始点bfs,求出每个点的编号d[i],d[i]表示从源点到i点通过至少几条残余流量大于0的边,能够到达i点。
2、只有那些满足d[u]+1=d[v]的边(u,v)才被视为存在,然后在这里面不断DFS找增广路并增广(其实随便走都可以),如果没有增广路了,那么返回步骤1,如果BFS不到汇点,证明算法结束。
该算法在第二步DFS有些优化,实现时可以自己想一想。一般不怎么加优化这个算法的效率都很不错了。】
代码
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int inf=100000000;
queue<int>que;
struct node{
int x,y,c,next;
}a[200001];
int n,m,s,t,len=-1,cur[10005],last[200001],dis[200001];
int minn(int xa,int ya)
{return xa>ya?ya:xa;}
void add(int xa,int ya,int ca)
{
a[++len].y=ya; a[len].c=ca; a[len].next=last[xa]; last[xa]=len;
a[++len].y=xa; a[len].c=0; a[len].next=last[ya]; last[ya]=len;
}
bool bfs()//找增广路,分层
{
memset(dis,0,sizeof(dis));
while (!que.empty()) que.pop();
dis[s]=1; que.push(s);
while (!que.empty())
{
int u=que.front(); que.pop();
for (int i=last[u];i;i=a[i].next)
if (a[i].c&&!dis[a[i].y])
{
dis[a[i].y]=dis[u]+1;
if (a[i].y==t) return 1;
que.push(a[i].y);
}
}
return 0;
}
int dfs(int xq,int maxf)//修改值
{
if (xq==t||!maxf) return maxf;
int ret=0;
for (int &i=cur[xq];i;i=a[i].next)
if (a[i].c&&dis[a[i].y]==dis[xq]+1)
{
int f=dfs(a[i].y,min(a[i].c,maxf-ret));
a[i].c-=f;
a[i^1].c+=f;
ret+=f;
if (maxf==ret) break;
}
return ret;
}
int dinic()
{
int ans=0;
while (bfs())
{
for (int i=1;i<=n;i++) cur[i]=last[i];
ans+=dfs(s,inf); //累加最大流
}
return ans;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
int xx,yy,cc;
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&xx,&yy,&cc);
add(xx,yy,cc);//建图,建图最重要
}
printf("%d",dinic());
}