题意:
给定一张有向图,每条边都有一个容量 c 和一个扩容费用 w。这里扩容费用是指将容量扩大 1 所需的费用。求:
在不扩容的情况下,1 到 n 的最大流;
将 1 到 n 的最大流增加 k 所需的最小扩容费用
题解:
第一问好说就是跑最大流,关键是第二问怎么想
两个方法:
其实本质也是一个,我们可以将扩容的费用转化为增加一点流量,花费W的费用,因为我们要让费用尽可能低,所以问题就成了最小费用流的模型
如何建图呢?
我们可以在第一问的基础上继续建图,也可以重新建图(个人倾向第一种)
如果是第一种,我们在跑完最大流后,利用残余网络继续建图,(第一问建图中每条弧的费用都是0的),我们再在第i条弧的两端之间建一条弧,弧的容量为INF,费用是cost[i],这样保证费用是最低的
但是题目要求是增加k,怎么能控制这个量呢?我们只需要在建立一个超级源点或者超级汇点(建立一个即可),连接S(T),容量为K,费用为0,也就是我们限制流入量或者流出量最多为K即可代码:
调了半天,终于写出来了。。。。
注意cnt要从1开始
因为0和1是一对相反边,2和3是一对。。。
#include<bits/stdc++.h>
#define inf 0x3f3f3f
#define mem(x,a) memset(x,a,sizeof(x))
typedef long long ll;
using namespace std;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
return s*w;
}
int n,m,k;
int S,T,cnt=1;
const int maxn=1e6+9;
struct node{
int u,v,w,cost,next;
}edge[maxn];
int head[maxn],dis[maxn],uu[maxn],vv[maxn],ww[maxn];
inline void add_edge(int u,int v,int w,int dis)
{
edge[++cnt].next=head[u];
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].cost=dis;
head[u]=cnt;
}
void add(int u,int v,int w,int dis)
{
add_edge(u,v,w,dis);
add_edge(v,u,0,-dis);
}
int level[maxn];
bool makelevel(int s,int t)
{
queue<int>q;
q.push(s);
mem(level,0);
level[s]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
// if(u==t)return 1;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].v;
int w=edge[i].w;
if(level[v]==0&&w!=0)
{
level[v]=level[u]+1;
q.push(v);
}
}
}
return level[t];
// return level[t];
}
int dfs(int u,int flow,int t)
{
if(u==t)return flow;
int sum=0;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].v;
int w=edge[i].w;
if(level[v]==level[u]+1&&w!=0)
{
int tmp=dfs(v,min(flow-sum,w),t);
edge[i].w-=tmp;
edge[i^1].w+=tmp;
sum+=tmp;
if(sum==flow)return sum;
}
}
return sum;
}
int dinic()
{
int ans=0;
while(makelevel(S,T))
{
ans+=dfs(S,inf,T);
}
return ans;
}
int fa[maxn],vis[maxn],xb[maxn],flow[maxn];
inline bool spfa(int s,int t)
{
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
queue<int> q;
while(!q.empty())
q.pop();
mem(fa,-1);
vis[s]=1;dis[s]=0;fa[s]=0;
flow[s]=inf;q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].v;
if(edge[i].w>0&&dis[v]>dis[u]+edge[i].cost)
{
dis[v]=dis[u]+edge[i].cost;
fa[v]=u;
xb[v]=i;
flow[v]=min(flow[u],edge[i].w);
if(!vis[v]){vis[v]=1,q.push(v);}
}
}
}
return fa[t]!=-1;
}
inline int mcmf(int s,int t)
{
int sum=0;
while(spfa(s,t))
{
int k=t;
while(k!=s)
{
edge[xb[k]].w-=flow[t];
edge[xb[k]^1].w+=flow[t];
k=fa[k];
}
// tot+=flow[t];
sum+=flow[t]*dis[t];
}
return sum;
}
int main()
{
cin>>n>>m>>k;
S=1;T=n;
for(int i=1;i<=m;i++)
{
int u,v,w;
cin>>uu[i]>>vv[i]>>ww[i]>>dis[i];
add(uu[i],vv[i],ww[i],0);
}
// add(S,1,inf,0);
// add(n,T,inf,0);
cout<<dinic()<<" ";
for(int i=1;i<=m;i++)
{
add(uu[i],vv[i],inf,dis[i]);
}
add(0,1,k,0);
cout<<mcmf(0,n);
}

京公网安备 11010502036488号