传送门biu~
费用流模板题,把一个点拆成两个,用1限流。跑费用流,费用流和最大流的区别是:费用流把最大流的bfs操作改成了spfa求最短路,每次增广的时候只增广在最短路上的点,可以保证每次都是最小费用。
#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;
int n,m,S,T,cost;
int head[505],nex[50005],to[50005],cap[50005],val[50005],tp=1;
int fir[505],dis[505];
bool b[505];
inline void add(int x,int y,int c,int v){
nex[++tp]=head[x];
head[x]=tp;
to[tp]=y;
cap[tp]=c;
val[tp]=v;
}
inline int spfa(){
queue<int>q;
for(int i=1;i<=2*n;++i) dis[i]=INF,b[i]=false;
dis[S]=0;q.push(S);
while(!q.empty()){
int x=q.front();q.pop();b[x]=false;
for(int i=head[x];i;i=nex[i]){
if(cap[i] && dis[x]+val[i]<dis[to[i]]){
dis[to[i]]=dis[x]+val[i];
if(!b[to[i]]){
q.push(to[i]);
b[to[i]]=true;
}
}
}
}
return dis[T]^INF;
}
int dfs(int x,int now){
if(x==T || !now){
cost+=now*dis[T];
return now;
}
int c=0;
b[x]=true;
for(int &i=fir[x];i;i=nex[i]){
if(!b[to[i]] && cap[i] && dis[to[i]]==dis[x]+val[i]){
int f=dfs(to[i],min(now,cap[i]));
now-=f;
cap[i]-=f;
cap[i^1]+=f;
c+=f;
if(!now) break;
}
}
return c;
}
inline int Dinic(){
int c=0;
while(spfa()){
for(int i=1;i<=2*n;++i) fir[i]=head[i];
c+=dfs(S,INF);
}
return c;
}
int main(){
scanf("%d%d",&n,&m);S=1;T=2*n;
for(int i=2;i<n;++i) add(i,i+n,1,0),add(i+n,i,0,0);
for(int i=1;i<=m;++i){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x+n,y,1,z);add(y,x+n,0,-z);
}
add(1,1+n,INF,0);add(n+1,1,0,0); add(n,n+n,INF,0);add(n+n,n,0,0);
int ans=Dinic();
printf("%d %d",ans,cost);
return 0;
}