前言
我枯了
题目:
数据:
思路:
先讲一些概念性的定义
名称 | 定义 |
---|---|
原点 | 只有流出的点 |
汇点 | 只有流入的点 |
流量 | 一条边流过的量 |
容量 | 一条边的最大流量 |
残量 | 容量 - 流量 |
然后在看基本性质
1.对于任意一个“管道”流量 容量 这个就很显然没什么好说
2.每个点(除原点和汇点)的入流和出流相等,就是原点流出多少就会有多少流入汇点,这个也很显然
3.对于一条有向边(u,v)k[u][v] = -k[v][u]
其实就是
最后来看一下算法
我们只学了dinic和一种慢到炸的算法
显然用dinic,毕竟快
这个算法就是每次以原点bfs求出每个边的编号,表示从原点到i通过至少几条残量大于0的边,再跑dfs找增广路并增广,如果没有增广路,返回步骤一,如果bfs没到汇点证明算法结束
:
#include <queue>
#include <cstdio>
#include <iostream>
#include <cstring>
const long long INF =1<<29;
using namespace std;
long long n, m, s, y, t;
long long h[100000],dis[100000];
long long tt;
queue<long long>hy;
struct node
{
long long y,w,to,next;
}e[500001];
long long read() //快读然并卵
{
long long x=0,flag=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{if(ch=='-')flag=-1;ch=getchar();}
while(ch>='0'&&ch<='9')
{x=x*10+ch-'0';ch=getchar();}
return x*flag;
}
void add (long long x, long long y, long long z)//加边
{
e[++tt] = (node){y, z, tt + 1, h[x]} ; h[x] = tt;//正向
e[++tt] = (node){x, 0, tt - 1, h[y]} ; h[y] = tt;//反向
}
void input ()//输入
{
n = read (); m = read (); s = read (); t = read ();
for (long long i = 1; i <= m; ++i)
{
long long x, y, z;
x=read (); y= read (); z = read ();
add (x, y, z);//建图
}
}
bool bfs ()//bfs判断
{
memset(dis,0x7f,sizeof(dis));//初始化
dis[s] = 0;
hy.push(s);
while (hy.size ())//bfs
{
long long x = hy.front ();
hy.pop ();
for (long long i = h[x]; i; i = e[i].next)//搜相邻的边
{
long long y = e[i].y;
if (dis[y] > dis[x] + 1 && e[i].w)
{
dis[y] = dis[x] + 1;
if (y == t) return 1;//找到
hy.push (y);
}
}
}
return 0;//没有
}
long long dfs (long long dep,long long diss)//找增广路
{
if (dep == t) return diss;
long long now_liuliang = 0;//当前流量
for (long long i = h[dep]; i; i = e[i].next)
{
long long y =e[i].y;
if (dis[y] == dis[dep] + 1 && e[i].w)
{
long long f = dfs (y, min(e[i].w, diss - now_liuliang));
if (!f) dis[y] = -1;//打标记
e[i].w -= f;//当前 - 流过
e[e[i].to].w += f;//反向 + 流过
now_liuliang += f;//正向 + 流过
if (now_liuliang == diss)break;
}
}
return now_liuliang;//返回
}
long long dinic ()//dinic
{
long long answer = 0;
while(bfs()) answer += dfs (s,INF);//能增广就增广
return answer ;
}
int main ()
{
input ();
printf("%lld",dinic());
return 0;
}
来源:CSDN
作者:SSL_whd
链接:https://blog.csdn.net/hunkwu/article/details/103740773