EK算法
落谷 P3376
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const ll mod = 1e9 + 7;
const int maxn = 3e5 + 10;
int n, m, st, ed;
int cnt, head[maxn];
int dis[maxn], vis[maxn], pre[maxn];
int flow[maxn], last[maxn];
struct EDGE{
int nxt, dis;
int to, flow;
} edge[maxn];
void add(int u, int v, int w, int d) {
edge[cnt].nxt = head[u];
edge[cnt].flow = w;
edge[cnt].to = v;
edge[cnt].dis = d;
head[u] = cnt++;
}
bool bfs(int s,int t) {
memset(flow,0x7f,sizeof(flow));
memset(dis,0x7f,sizeof(dis));
memset(vis,0,sizeof(vis));
queue <int> Q;
Q.push(s);
vis[s]=1,dis[s]=0,pre[t]=-1;
while(!Q.empty()) {
int temp = Q.front();
Q.pop();
vis[temp] = 0;
for(int i=head[temp]; ~i; i=edge[i].nxt) {
int v = edge[i].to;
if(edge[i].flow>0 && dis[v]>dis[temp]+edge[i].dis) {
dis[v] = dis[temp]+edge[i].dis;
pre[v] = temp;
last[v] = i;
flow[v] = min(flow[temp], edge[i].flow);
if(!vis[v]) {
vis[v] = 1;
Q.push(v);
}
}
}
}
return pre[t]!=-1;
}
int EK(int s, int t) {
int maxflow=0, mincost=0;
while(bfs(s,t)) {
int now = t;
maxflow += flow[t];
mincost += flow[t]*dis[t];
while(now!=s) {
edge[last[now]].flow -= flow[t];
edge[last[now]^1].flow += flow[t];
now = pre[now];
}
}
return maxflow;
}
int main() {
while(~scanf("%d%d%d%d", &n, &m, &st, &ed)){
cnt = 0;
memset(head,-1,sizeof(head));
for(int i=0; i<m; i++){
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
add(x,y,z,1);
add(y,x,0,1);
}
int ans = EK(st,ed);
printf("%d\n", ans);
}
}
Dinic算法
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const ll INF = LONG_LONG_MAX;
const int maxn = 3e5 + 5;
int n, m, st, ed;
ll ans, dis[maxn];
int cnt, head[maxn], cur[maxn];
struct EDGE {
int nxt, to;
ll w;
} edge[maxn];
void add(int u, int v, ll w) {
edge[cnt].nxt = head[u];
edge[cnt].w = w;
edge[cnt].to = v;
head[u] = cnt++; // 从0开始
}
int bfs() {
memset(dis, -1, sizeof(dis));
dis[st] = 0;
queue <int> Q;
Q.push(st);
while(!Q.empty()) {
int u = Q.front(); Q.pop();
for(int i=head[u]; ~i; i=edge[i].nxt) {
int v = edge[i].to;
if(dis[v]==-1 && edge[i].w>0) {
dis[v] = dis[u] + 1;
Q.push(v);
}
}
}
return dis[ed] != -1; // 判断是否联通。
}
ll dfs(int u, ll exp) {
if(u == ed) return exp; // 到达终点,全部接受。
ll flow = 0, tmp = 0;
for(int &i=cur[u]; ~i; i=edge[i].nxt) { // 当前弧优化
int v = edge[i].to;
if(dis[v]==dis[u]+1 && edge[i].w>0) {
tmp = dfs(v, min(exp, edge[i].w));
if(!tmp) continue;
exp -= tmp; // 流量限制-流量,后边有判断。
flow += tmp;
edge[i].w -= tmp; // 路径上的边残量减少
edge[i^1].w += tmp; // 流经的边的反向边残量增加。
if(!exp) break; // 判断是否在限制边缘
}
}
return flow;
}
int main() {
while(~scanf("%d%d%d%d", &n, &m, &st, &ed)) {
cnt = ans = 0;
memset(head, -1, sizeof(head));
int x, y; ll z;
for(int i=1; i<=m; i++) {
scanf("%d%d%lld", &x, &y, &z);
add(x, y, z);
add(y, x, 0); // 相邻建边。
}
while(bfs()) {
for(int i=0; i<=n; i++) cur[i] = head[i];
ans += dfs(st, INF);
}
printf("%lld\n", ans);
}
}