bzoj1834 ZJOI2010网络扩容(费用流)

给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。

求:

1、在不扩容的情况下,1到N的最大流;

2、将1到N的最大流增加K所需的最小扩容费用。

其中\(n \le 1000,m \le 5000,k \le 10\)

网络流题,复杂度都是没用的了....

第一问就是一个裸的最大流

现在我们考虑第二问QwQ

最小扩容费用,我们是不是可以对于原图中的\(u->v\)的边,添加一条\(u->v\),流量为\(inf\),费用为\(w\)的边,这样就可以实现扩容了。可是我们怎么限制最大流增加k呢?

我们可以新建一个t,然后从原来的\(t\)连向现在的t,费用为0,流量为\(maxflow+k\)的边,然后直接跑费用流即可

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>

using namespace std;

inline int read()
{
   int x=0,f=1;char ch=getchar();
   while (!isdigit(ch)){if (ch==‘-‘) f=-1;ch=getchar();}
   while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
   return x*f;
}

const int maxn = 2018;
const int maxm = 1e6+1e2;
const int inf = 1e9;

int n,m,k;
int x[maxm],y[maxm],w[maxm],f[maxm];
int point[maxn],nxt[maxm],to[maxm],cost[maxm],flow[maxm];
int pre[maxm];
int dis[maxn],vis[maxn];
int cnt=1;
int anscost,ansflow;
queue<int> q;
int s,t;
int from[maxn];

void addedge(int x,int y,int w,int f)
{
    nxt[++cnt]=point[x];
    to[cnt]=y;
    cost[cnt]=w;
    flow[cnt]=f;
    pre[cnt]=x;
    point[x]=cnt;
}

void insert(int x,int y,int w,int f)
{
    addedge(x,y,w,f);
    addedge(y,x,-w,0);
}

void init()
{
    cnt=1;
    memset(point,0,sizeof(point));
    memset(dis,127/3,sizeof(dis));
    memset(vis,0,sizeof(vis));
}

bool spfa(int s)
{
    memset(dis,127/3,sizeof(dis));
    memset(vis,0,sizeof(vis));
    vis[s]=1;
    dis[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int x = q.front();
        q.pop();
        vis[x]=0;
        for (int i=point[x];i;i=nxt[i])
        {
            int p = to[i];
            if (flow[i]>0 && dis[p]>dis[x]+cost[i])
            {
                from[p]=i;
                dis[p]=dis[x]+cost[i];
                if (!vis[p])
                {
                    q.push(p);
                    vis[p]=1;
                }
            }
        }
    }
    if (dis[t]>=dis[t+1]) return false;
    else return true;
}

void mcf()
{
    int x= inf;
    for (int i=from[t];i;i=from[pre[i]]) x=min(x,flow[i]);
    ansflow+=x;
    for (int i=from[t];i;i=from[pre[i]])
    {
        flow[i]-=x;
        flow[i^1]+=x;
        anscost+=cost[i]*x;
    }
}

void solve()
{
    while (spfa(s))
    {
        mcf();
    }
}
int main()
{
  n=read();
  m=read();
  k=read();
  s=1;
  t=n;
  for (int i=1;i<=m;i++) x[i]=read(),y[i]=read(),f[i]=read(),w[i]=read();
  for (int i=1;i<=m;i++) insert(x[i],y[i],0,f[i]);
  solve();
  //cout<<ansflow<<endl;
  int ff=ansflow;
  ansflow=0;anscost=0;
  init();
  for (int i=1;i<=m;i++) insert(x[i],y[i],0,f[i]),insert(x[i],y[i],w[i],inf);
  t=n+1;
  insert(n,n+1,0,ff+k);
  solve();
  cout<<ff<<" "<<anscost;
  return 0;
}

原文地址:https://www.cnblogs.com/yimmortal/p/10160854.html

时间: 2024-12-12 15:28:27

bzoj1834 ZJOI2010网络扩容(费用流)的相关文章

luogu P2604 [ZJOI2010]网络扩容 |费用流

题目描述 给定一张有向图,每条边都有一个容量\(C\)和一个扩容费用\(W\).这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. 输入格式 输入文件的第一行包含三个整数\(N,M,K\),表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数\(u,v,C,W\),表示一条从u到v,容量为C,扩容费用为W的边. 输出格式 输出文件一行包含两个整数,分别表示问题1和问题2的答案. 利用残余网

[ZJOI2010][bzoj1834] 网络扩容 [费用流]

题面 传送门 思路 第一问:无脑网络流跑一波 第二问: 先考虑一个贪心的结论:扩容出来的扩容流量一定要跑满 证明显然 因此我们可以把扩容费用可以换个角度思考,变成增加一点流量,花费W的费用 这样,我们就得到了一个最小费用流的模型 只要在原图基础上,对于每个原图边,加一条费用为W,无限容量的边,而原图中的所有边费用为0,就可以模拟原题需要的情况了 最后一个问题:流量增加限制K怎么处理? 我们虽然可以用spfa的费用流,一次一次增加,直到K,但是这样也太慢chou了吧? 不怕,我们加一个n+1号点,

[ZJOI2010]网络扩容 (最大流 + 费用流)

题目描述 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. 输入输出格式 输入格式: 输入文件的第一行包含三个整数N,M,K,表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边. 输出格式: 输出文件一行包含两个整数,分别表示问题1和问题2的答案. 输入输出样例 输入样例#

bzoj 1834: [ZJOI2010]network 网络扩容 -- 最大流+费用流

1834: [ZJOI2010]network 网络扩容 Time Limit: 3 Sec  Memory Limit: 64 MB Description 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. Input 输入文件的第一行包含三个整数N,M,K,表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数u,v,C,W,表示一

【bzoj1834】[ZJOI2010]network 网络扩容 最大流+最小费用流

题目描述 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. 输入 输入文件的第一行包含三个整数N,M,K,表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边. 输出 输出文件一行包含两个整数,分别表示问题1和问题2的答案. 样例输入 5 8 2 1 2 5 8 2 5 9

[zjoi2010]网络扩容

描述 Description  给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. 输入格式 Input Format 输入文件的第一行包含三个整数N,M,K,表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边. 输出格式 Output Format 输出文件一行包含两个整数

洛谷 P2604 [ZJOI2010]网络扩容

题目描述 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. 输入输出格式 输入格式: 输入文件的第一行包含三个整数N,M,K,表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边. 输出格式: 输出文件一行包含两个整数,分别表示问题1和问题2的答案. 输入输出样例 输入样例#

p2604 [ZJOI2010]网络扩容

传送门 分析 第一问就是最大流 第二问用一个源点向1连一条流量为第一问答案+k的边然后跑费用流即可 代码 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cctype> #include<cmath> #include<cstdlib> #include<

【[ZJOI2010]网络扩容】

题目 第一问直接板子敲上去 第二问并不明白直接在残量网络上加边的神仙做法 非常显然我们需要让流量加\(k\),那么我们就使得网络里的总流量为\(maxf+k\),\(maxf\)是第一问求出来的最大流 所以搞一个超级源点,向\(1\)连一条流量是\(maxf+k\)费用是\(0\)的边,之后在原来的图的基础上再给每条边加一条流量为\(inf\),费用为相应费用的边 这样让它自己在里面流就必然会流出来\(maxf+k\)的流量 求出最小费用就好了 代码 #include<algorithm> #