最小费用最大流肯定要保证最大流,所以它和最大流有一些类似的性质。如果把费用看成边,就可以每次走最短路(保证费用最小),走到不能走为止(保证最大流)。费用流版的ek就是这样。需要注意的是,反向弧的边权为它对应的正向弧的费用的相反数,所以最短路要用spfa来求。
费用流版的dinic,又叫zkw费用流,还是多路增广的思想。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cstdlib> #include<cmath> #include<iomanip> #include<queue> #define maxn 5010 #define maxm 100010 using namespace std; int fir[maxn],nxt[maxm],v[maxm],fl[maxm],w[maxm],cnt; int n,m,dis[maxn],s,t,inf[5],mincost,maxflow; int p[maxn],flp[maxn],kp[maxn]; bool vis[maxn]; int read() { int x = 0, f = 1; char c = getchar(); while (!isdigit(c)) { if (c == '-') f = -1; c = getchar(); } while(isdigit(c)) x = x*10 + c - '0', c = getchar(); return x*f; } void addedge(int u1,int v1,int fl1,int w1) { v[cnt]=v1,w[cnt]=w1,fl[cnt]=fl1,nxt[cnt]=fir[u1],fir[u1]=cnt++; v[cnt]=u1,w[cnt]=-w1,fl[cnt]=0,nxt[cnt]=fir[v1],fir[v1]=cnt++; } bool spfa() { memset(dis,0x7f,sizeof(dis)); memset(vis,0,sizeof(vis)); queue<int>q; dis[s]=0; vis[s]=1; flp[s]=inf[0]; q.push(s); while(!q.empty()) { int u=q.front();q.pop(); for(int k=fir[u];k!=-1;k=nxt[k]) { int vv=v[k]; if(fl[k]>0) { if(dis[vv]>dis[u]+w[k]) { dis[vv]=dis[u]+w[k]; if(!vis[vv])q.push(vv); p[vv]=u; kp[vv]=k; flp[vv]=min(flp[u],fl[k]); vis[vv]=1; } } } vis[u]=0; } return dis[t]==inf[0]?0:1; } void dfs() { for(int i=t;i!=s;i=p[i]) { mincost+=w[kp[i]]*flp[t]; fl[kp[i]]-=flp[t]; fl[kp[i]^1]+=flp[t]; } maxflow+=flp[t]; return; } int main() { memset(fir,-1,sizeof(fir)); memset(inf,0x7f,sizeof(inf)); n=read(),m=read(),s=read(),t=read(); for(int i=1;i<=m;i++) { int x=read(),y=read(),z=read(),k=read(); addedge(x,y,z,k); } while(spfa())dfs(); cout<<maxflow<<" "<<mincost; }
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cstdlib> #include<cmath> #include<iomanip> #include<queue> #define maxn 5010 #define maxm 100010 using namespace std; int fir[maxn],nxt[maxm],v[maxm],fl[maxm],w[maxm],cnt; int n,m,dis[maxn],s,t,inf[5],mincost,maxflow; bool vis[maxn]; queue<int >q; int read() { int x = 0, f = 1; char c = getchar(); while (!isdigit(c)) { if (c == '-') f = -1; c = getchar(); } while(isdigit(c)) x = x*10 + c - '0', c = getchar(); return x*f; } void addedge(int u1,int v1,int fl1,int w1) { v[cnt]=v1,w[cnt]=w1,fl[cnt]=fl1,nxt[cnt]=fir[u1],fir[u1]=cnt++; v[cnt]=u1,w[cnt]=-w1,fl[cnt]=0,nxt[cnt]=fir[v1],fir[v1]=cnt++; } bool spfa() { memset(dis,0x7f,sizeof(dis)); memset(vis,0,sizeof(vis)); dis[t]=0; vis[t]=1; q.push(t); while(!q.empty()) { int u=q.front();q.pop(); for(int k=fir[u];k!=-1;k=nxt[k]) { if(fl[k^1]>0) { if(dis[v[k]]>dis[u]-w[k]) { dis[v[k]]=dis[u]-w[k]; if(!vis[v[k]]){q.push(v[k]);} vis[v[k]]=1; } } } vis[u]=0; } while(!q.empty())q.pop(); return dis[s]==inf[0]?0:1; } int dfs(int u,int nowflow) { if(u==t || nowflow==0)return nowflow; vis[u]=1; int sum=0,tmp; for(int k=fir[u];k!=-1;k=nxt[k]) { if(nowflow<=0)break; if(fl[k]>0 && dis[v[k]]+w[k]==dis[u] && vis[v[k]]==0 && (tmp=dfs(v[k],min(fl[k],nowflow)))>0) { nowflow-=tmp; sum+=tmp; fl[k]-=tmp; fl[k^1]+=tmp; mincost+=tmp*w[k]; } } vis[u]=0; return sum; } int main() { memset(fir,-1,sizeof(fir)); memset(inf,0x7f,sizeof(inf)); n=read(),m=read(),s=read(),t=read(); for(int i=1;i<=m;i++) { int x=read(),y=read(),z=read(),k=read(); addedge(x,y,z,k); } while(spfa()) { memset(vis,0,sizeof(vis)); maxflow+=dfs(s,inf[0]); } cout<<maxflow<<" "<<mincost; }