一点小小的吐槽
我愿称luogu的这道网络流模板题为最强模板题
第一次发现当前弧优化还有这些奇奇怪怪的小细节
那个flow==0的判断位置查了我两个小时
最气的是查出来后还贼有道理 还喷不了它
代码库
dinic
本人使用dinic 由于网络上题解众多 此处直接放出代码 并附上在连交10发中发现的小细节
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
#define REG register
#define rep(i,a,b) for(REG int i=a;i<=b;i++)
inline char getc(){
static char buf[1<<14],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++;
}
inline int scan(){
REG int x=0; REG char ch=0;
while(ch<48) ch=getc();
while(ch>=48) x=x*10+ch-48,ch=getc();
return x;
}
//我一开始开的是5002 后来意识到下标是从2开始的 于是开大了一点 影响未知
const int N=202,M=5005;
const ll INF=1e18;
//这玩意我一开始没开long long
//虽然每一条边的容量都 <2147483648 但是到汇点的流量可以是多条边进去 所以是会超的
//不开long long见祖宗
int head[N],nex[M<<1],to[M<<1]; ll wei[M<<1];
inline void addEdge(int u,int v,int w){
static int cc=1; //由2起的标号 便于取反 一开始忘了wa了1发
nex[++cc]=head[u]; to[cc]=v; wei[cc]=w; head[u]=cc;
}
int n,m,s,t,d[N],cur[N],Q[N],l,r;
inline bool bfs(){
//rep(i,1,n) if(cur[i]==head[i]) printf("???
");
rep(i,1,n) cur[i]=d[i]=0;
l=1,r=0; Q[++r]=s; d[s]=1;
REG int u;
while(l<=r){
u=Q[l++]; cur[u]=head[u];
for(REG int i=head[u];i;i=nex[i]){
if(d[to[i]]||!wei[i]) continue;
Q[++r]=to[i]; d[to[i]]=d[u]+1;
}
}
return d[t];
}
inline ll dfs(int u,ll flow){
if(u==t) return flow;
//把temp开在for外面会快一点(不过这一点很显然就是了)
REG ll rest=0,temp;
//经测试register的引用完全没有问题 至于是否未知的bug我就不懂了
for(REG int &i=cur[u];i;i=nex[i]){
//若此处写成 for(REG int &i=cur[u];i&&flow;i=nex[i]) 然后后面不break 就会T
if(d[to[i]]==d[u]+1&&wei[i]){
temp=dfs(to[i],min(flow,wei[i]));
rest+=temp; flow-=temp;
wei[i]-=temp; wei[i^1]+=temp;
}
//在此处break与放在for函数的区别在于如果此边还有残量 这一边就不会被当前弧优化跳过
if(!flow) break;
}
//此处有个剪枝 虽然没有这个也会因为当前弧到底而退出 不过加上还是快了点
if(rest==0) d[u]=0;
return rest;
}
int main(){
//freopen("P3376_9.in","r",stdin);
n=scan(),m=scan(),s=scan(),t=scan();
REG int u,v,w;
while(m--){
u=scan(); v=scan(); w=scan();
addEdge(u,v,w); addEdge(v,u,0);
}
REG ll res=0;
while(bfs()) res+=dfs(s,INF);
printf("%lld
",res);
return 0;
}