先贴学习博客:博客
遇到的题目:题目链接
牛客练习赛65
E-游走配对
官方题解:
感觉很少遇到最小费用最大流题,可能以前遇到过,只是水平不够 没看到那题,现在看到了就顺手补补吧。
今天先贴板子,先学会怎么用 以后有时间再学,写个博客插个眼。
最小费用最大流模版.求最大费用最大流建图时把费用取负即可。
作者:kkksx
链接:https://ac.nowcoder.com/discuss/439404?type=101&order=0&pos=2&page=1&channel=1004&source_id=discuss_tag
来源:牛客网
#include<bits/stdc++.h>
#define N 405
#define M 200005
using namespace std;
int n,m,q,s,t;
int in[N],out[N],a[N],b[N];
int dis[N],flow[N],exist[N];
int pre[N],preedge[N];
struct Edge
{
int next,to,flow,dis;
}edge[M << 1]; int head[N],cnt = 1;
void add_edge(int from,int to,int flow,int dis)
{
edge[++cnt].next = head[from];
edge[cnt].to = to;
edge[cnt].flow = flow;
edge[cnt].dis = dis;
head[from] = cnt;
}
void add(int from,int to,int flow,int dis)
{
add_edge(from,to,flow,dis);
add_edge(to,from,0,-dis);
}
bool spfa(int s,int t)
{
memset(dis,100,sizeof(dis));
memset(flow,100,sizeof(flow));
memset(exist,0,sizeof(exist));
queue<int> q;
pre[t]=-1; exist[s]=1; dis[s]=0; q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();exist[u]=0;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(edge[i].flow>0&&dis[v]>dis[u]+edge[i].dis)
{
dis[v]=dis[u]+edge[i].dis;
flow[v]=min(edge[i].flow,flow[u]);
pre[v]=u;
preedge[v]=i;
if(!exist[v])
{
exist[v]=1;
q.push(v);
}
}
}
}
return pre[t]!=-1;
}
int MCMF()
{
int ret = 0;
while(spfa(s,t))
{
ret += flow[t] * dis[t];
int now = t;
while(now!=s)
{
edge[preedge[now]].flow -= flow[t];
edge[preedge[now]^1].flow += flow[t];
now=pre[now];
}
}
return ret;
}
int main()
{
// freopen("9.in","r",stdin);
// freopen("e9.out","w",stdout);
scanf("%d%d%d",&n,&m,&q);
s = 0,t = N - 1;
for(int i=1;i<=n;++i)
{
int a,b; scanf("%d%d",&a,&b);
for(int j=1;j<=q * 2;++j) add(i,i + n,1,a + (j - 1) * b);
}
for(int i=1;i<=m;++i)
{
int x,y;
scanf("%d%d",&x,&y);
add(x + n,y,q * 2,0);
add(y + n,x,q * 2,0);
}
for(int i=1;i<=q;++i)
{
int x; scanf("%d",&x);
add(s,x,1,0);
}
for(int i=1;i<=q;++i)
{
int x; scanf("%d",&x);
add(x + n,t,1,0);
}
printf("%d\n",MCMF());
return 0;
}