洛谷3381
最小费用最大流模板题
思路和网络流的EK算法类似,
1.建正向边,反向边(反向边流量为0,花费为负数:走反向边即取消上次走过后增加的值,因此如此定义)
2.用spfa增广,找到流量大于0且由花费决定的最小dis[ t ],接着回溯,找到能通过的最大流量(minn)
3.ansflow+=minn;anscost+=minn*dis[t];
4.重复2.3步骤,直至无法增广,即为答案
#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define INF 0x33333333 using namespace std; const int N=5002,M=50002; int n,m,s,t,cnt=-1,vis[N],dis[N],head[N]; int pv[N],pe[N]; struct data{int v,flow,cos,next;}edge[2*M]; queue<int>q; inline void read(int &x){ char ch=getchar();x=0; while(!isdigit(ch))ch=getchar(); while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} } inline bool spfa(int S,int T) { memset(dis,0x33,sizeof dis); memset(vis,0,sizeof vis); q.push(S),vis[S]=1,dis[S]=0; while(!q.empty()) { int now=q.front();q.pop();vis[now]=0; for (int i=head[now];~i;i=edge[i].next)//注意不是i>0;会出现第0条边 if (edge[i].flow>0 && dis[edge[i].v]>dis[now]+edge[i].cos) { dis[edge[i].v]=dis[now]+edge[i].cos; pe[edge[i].v]=i,pv[edge[i].v]=now; if (!vis[edge[i].v]) vis[edge[i].v]=1,q.push(edge[i].v); } } return dis[T]<INF; } inline void Putans(int x){ if(x>=10)Putans(x/10);putchar(x%10+'0'); } inline void mfmc(int S,int T){ int Cos=0,Flow=0,minn; while(spfa(S,T)){ minn=INF; for(int i=T;i!=S;i=pv[i])minn=min(minn,edge[pe[i]].flow); Cos+=minn*dis[T]; Flow=Flow+minn; for(int i=T;i!=S;i=pv[i]){edge[pe[i]].flow-=minn;edge[pe[i]^1].flow+=minn;} } Putans(Flow);printf(" ");Putans(Cos);//printf("%d %d",Flow,Cos); } inline void insert(int u,int v,int flow,int cost){ edge[++cnt].v=v; edge[cnt].flow=flow;edge[cnt].cos=cost;edge[cnt].next=head[u];head[u]=cnt; } int main(){ read(n);read(m);read(s);read(t); memset(head,-1,sizeof(head));//一定要赋值-1,否则spfa时出现第0条边,无限循环 memset(edge,-1,sizeof(edge)); for(int i=1;i<=m;i++){//tot初值为-1(保证 ^1后是反向边) int u,v,flow,cost; read(u);read(v);read(flow);read(cost); insert(u,v,flow,cost);insert(v,u,0,-cost);//flow要赋值0,否则其初值为-1 } mfmc(s,t); }