划水啊,就是最小费用最大流的模板,只是标记一下自己会了这种算法。
正解就是SPFA+EK,在SPFA扩展的过程中加入EK的判断——这条边的流量是否还有剩余。
然后在所有节点都扩展完毕后进行EK的流量修改,最后统计答案。
附上AC代码:
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
struct note{
int from,to,w,v,nt;
}side[100010];
queue <int> que;
int n,m,s,t,x,y,w,v,h[5010],dis[5010],f[5010],pre[5010],flow,cost,num;
bool b[5010];
void add(int x,int y,int w,int v){
side[num]=(note){x,y,w,v,h[x]};
h[x]=num++;
}
bool spfa(){
for (int i=1; i<=n; ++i) dis[i]=1e9,b[i]=0;
b[s]=1,dis[s]=0,f[s]=2e9,que.push(s);
while (!que.empty()){
int p=que.front();que.pop(),b[p]=0;
for (int i=h[p]; ~i; i=side[i].nt)
if (side[i].w&&dis[side[i].to]>dis[p]+side[i].v){
dis[side[i].to]=dis[p]+side[i].v;
pre[side[i].to]=i;
f[side[i].to]=min(f[p],side[i].w);
if (!b[side[i].to]){
b[side[i].to]=1;
que.push(side[i].to);
}
}
}
if (dis[t]==1e9) return 0;
flow+=f[t];
cost+=f[t]*dis[t];
for (int i=t; i!=s; i=side[pre[i]].from){
side[pre[i]].w-=f[t];
side[pre[i]^1].w+=f[t];
}
return 1;
}
int main(void){
scanf("%d%d%d%d",&n,&m,&s,&t);
memset(h,-1,sizeof h);
for (int i=1; i<=m; ++i){
scanf("%d%d%d%d",&x,&y,&w,&v);
add(x,y,w,v),add(y,x,0,-v);
}
while (spfa());
printf("%d %d",flow,cost);
return 0;
}