最小费用最大流
传送门
这里详(jian)细(dan)解释一下最小费用最大流。
最大流会不会?
会!
最短路会不会?
会!
那你不就会这个题怎么写了。。。
算了,最小费用最大流是要求在最小费用的前提下求最大流,那么我们显然要优先考虑最小费用吗,想想我们求最大流的过程。
我们就可以将费用定成边权,将bfs求增广路变成最短路求增广路,这样就能保证最小费用了,剩下的不就是最大流的事了吗?
zkw费用流
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int tmp=1,sum,n,m,son[200001],ans,nex[200001],h[200001],v[200001],s,t,c[200001],dis[200001],slack[200001];
bool used[200001];
const int inf=1e9;
void ins(int x,int y,int z,int d)
{
son[++tmp]=y;nex[tmp]=h[x];h[x]=tmp;v[tmp]=d;c[tmp]=z;
son[++tmp]=x;nex[tmp]=h[y];h[y]=tmp;v[tmp]=-d;c[tmp]=0;
}
int KM(int x,int flow)
{
if(x==t){sum+=flow*dis[t];return flow;}
used[x]=1;
int cp=flow;
for(int i=h[x];i;i=nex[i])
{
int l=son[i];
if(!used[l]&&c[i])
{
if(dis[x]+v[i]-dis[l]==0)
{
int y=KM(l,min(c[i],cp));
cp-=y,c[i]-=y,c[i^1]+=y;
if(!cp)return flow;
}
else slack[l]=min(slack[l],dis[x]+v[i]-dis[l]);
}
}
return flow-cp;
}
bool dfs()
{
int mx=inf;
for(int i=1;i<=n;i++)
if(!used[i])mx=min(mx,slack[i]),slack[i]=inf;
if(mx==inf)return 1;
for(int i=1;i<=n;i++)
if(!used[i])dis[i]+=mx;
return 0;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1,x,y,z,w;i<=m;i++)
{
scanf("%d%d%d%d",&x,&y,&z,&w);
ins(x,y,z,w);
}
memset(slack,63,sizeof(slack));
do{
do{
memset(used,0,sizeof(used));
tmp=KM(s,inf),ans+=tmp;
}while(tmp);
}while (!dfs());
printf("%d %d",ans,sum);
}
EK
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
inline void read(int &x) {
char ch; bool ok;
for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
#define min(a,b) (a<b?a:b)
#define rg register
queue<int>q;int n,m,s,t,num,b[200001],c[200001],pre[200001],dis[100010],nxt[200001],h[100010],v[200001],w[200001],cnt=1,inf=1e9,ans,que[200001];bool vis[100010];
inline void add(int x,int y,int z,int u)
{
pre[++cnt]=y,nxt[cnt]=h[x],h[x]=cnt,v[cnt]=z,w[cnt]=u,
pre[++cnt]=x,nxt[cnt]=h[y],h[y]=cnt,v[cnt]=0,w[cnt]=-u;
}
bool spfa(int s)
{
memset(dis,63,sizeof dis);
q.push(s),dis[s]=0;
while(!q.empty())
{
int x=q.front();q.pop(),vis[x]=0;
for(rg int i=h[x];i;i=nxt[i])
if(v[i]&&dis[pre[i]]>dis[x]+w[i])
{
dis[pre[i]]=dis[x]+w[i],b[pre[i]]=x,c[pre[i]]=i;
if(!vis[pre[i]])vis[pre[i]]=1,q.push(pre[i]);
}
}
return dis[t]<inf;
}
int getans()
{
int mn=inf;
for(rg int i=t;i!=s;i=b[i])mn=min(v[c[i]],mn);
for(rg int i=t;i!=s;i=b[i])v[c[i]]-=mn,v[c[i]^1]+=mn;
num+=mn;
return dis[t]*mn;
}
int main()
{
read(n),read(m),read(s),read(t);
for(rg int i=1,x,y,z,w;i<=m;i++)read(x),read(y),read(z),read(w),add(x,y,z,w);
while(spfa(s))ans+=getans();
printf("%d %d\n",num,ans);
}