练习题
P3381 【模板】最小费用最大流
链接:https://www.luogu.com.cn/problem/P3381
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
namespace MCMF
{
const int MAXN=5000+10,MAXM=1e5+10,inf=2e9;
int dis[MAXN],visit[MAXN],pre[MAXN],maxflow,mincost;
int maxvex,head[maxn],ecnt,s,t;
void init(int ss,int tt,int n)
{
ecnt=1,maxvex=n;
for(int i=0; i<=maxvex; ++i) head[i]=-1;
s=ss,t=tt;
}
struct Edge
{
int nxt,to,flow,cost;
} edges[MAXM];
void add(int u,int v,int flow,int cost)
{
edges[++ecnt]= {head[u],v,flow,cost},head[u]=ecnt;
edges[++ecnt]= {head[v],u,0,-cost},head[v]=ecnt;
}
bool spfa()
{
for(int i=0; i<=maxvex; ++i) dis[i]=inf,visit[i]=pre[i]=0;
dis[s]=0;
queue<int> q;
q.push(s);
visit[s]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
visit[u]=0;
for(int i=head[u]; i!=-1; i=edges[i].nxt)
{
int v=edges[i].to,cost=edges[i].cost;
if(edges[i].flow&&dis[v]>dis[u]+cost)
{
dis[v]=dis[u]+cost;
pre[v]=i;
if(!visit[v]) visit[v]=1,q.push(v);
}
}
}
return dis[t]<inf;
}
void augment()
{
int p=t,curflow=inf;
while(pre[p])
{
curflow=min(curflow,edges[pre[p]].flow);
p=edges[pre[p]^1].to;
}
maxflow+=curflow,mincost+=curflow*dis[t];
p=t;
while(pre[p])
{
edges[pre[p]].flow-=curflow;
edges[pre[p]^1].flow+=curflow;
p=edges[pre[p]^1].to;
}
}
void mcmf()
{
maxflow=0,mincost=0;
while(spfa()) augment();
}
};
int n,m,s,t;
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
MCMF::init(s,t,n);
for(int i=1; i<=m; ++i)
{
int u,v,w,c;
scanf("%d%d%d%d",&u,&v,&w,&c);
MCMF::add(u,v,w,c);
}
MCMF::mcmf();
printf("%d %d\n",MCMF::maxflow,MCMF::mincost);
return 0;
}
H. Minimum-cost Flow 2020牛客第一场 (最小费用最大流)
链接:https://ac.nowcoder.com/acm/contest/5666/H
题意:给定一张带费用的图,单位费用为 c i c_i ci,给出 q 次询问,每次限定每条边的容量为 u i v i \frac {u_i}{v_i} viui ,问从 1 到 n 流过 1 的流量需要的最小费用是多少
思路:设
c
o
s
t
(
x
,
y
)
cost(x,y)
cost(x,y) 表示每条边的容量为
x
x
x ,流过
y
y
y 流量的最小花费,则
c
o
s
t
(
u
i
v
i
,
1
)
=
c
o
s
t
(
1
,
v
i
u
i
)
×
u
i
v
i
cost(\frac {u_i}{v_i},1) =cost(1,\frac{v_i}{u_i})\times \frac{u_i}{v_i}
cost(viui,1)=cost(1,uivi)×viui
因此,只需要将边的容量设为 1 ,做一次费用流,记录每条增广路得到的最小费用。然后计算流过 v i u i \frac{v_i}{u_i} uivi 的流量需要的费用,最后乘上 u i v i \frac{u_i}{v_i} viui 即可
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
namespace MCMF
{
const int MAXN=50+10,MAXM=200+10,inf=2e9;
int dis[MAXN],visit[MAXN],pre[MAXN],maxflow,mincost;
int maxvex,head[maxn],ecnt,s,t;
vector<int> dd;
void init(int ss,int tt,int n)
{
ecnt=1,maxvex=n;
for(int i=0; i<=maxvex; ++i) head[i]=-1;
s=ss,t=tt;
dd.clear();
}
struct Edge
{
int nxt,to,flow,cost;
} edges[MAXM];
void add(int u,int v,int flow,int cost)
{
edges[++ecnt]= {head[u],v,flow,cost},head[u]=ecnt;
edges[++ecnt]= {head[v],u,0,-cost},head[v]=ecnt;
}
bool spfa()
{
for(int i=0; i<=maxvex; ++i) dis[i]=inf,visit[i]=pre[i]=0;
dis[s]=0;
queue<int> q;
q.push(s);
visit[s]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
visit[u]=0;
for(int i=head[u]; i!=-1; i=edges[i].nxt)
{
int v=edges[i].to,cost=edges[i].cost;
if(edges[i].flow&&dis[v]>dis[u]+cost)
{
dis[v]=dis[u]+cost;
pre[v]=i;
if(!visit[v]) visit[v]=1,q.push(v);
}
}
}
return dis[t]<inf;
}
void augment()
{
dd.push_back(dis[t]);
int p=t,curflow=inf;
while(pre[p])
{
curflow=min(curflow,edges[pre[p]].flow);
p=edges[pre[p]^1].to;
}
maxflow+=curflow,mincost+=curflow*dis[t];
p=t;
while(pre[p])
{
edges[pre[p]].flow-=curflow;
edges[pre[p]^1].flow+=curflow;
p=edges[pre[p]^1].to;
}
}
void mcmf()
{
maxflow=0,mincost=0;
while(spfa()) augment();
}
};
int n,m,s,t;
ll pref[maxn];
int main()
{
while(~scanf("%d%d",&n,&m))
{
MCMF::init(1,n,n);
for(int i=1;i<=m;++i)
{
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
MCMF::add(u,v,1,c);
}
MCMF::mcmf();
auto d=MCMF::dd;
m=d.size();
for(int i=1;i<=m;++i)
pref[i]=pref[i-1]+d[i-1];
int q,u,v;
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&u,&v);
if(1ll*m*u<v) puts("NaN");
else
{
int x=v/u;
int r=v%u;
ll w=1ll*pref[x]*u+1ll*r*d[x];
ll z=__gcd(w,1ll*v);
printf("%lld/%lld\n",w/z,v/z);
}
}
}
return 0;
}