zoukankan      html  css  js  c++  java
  • BZOJ 1834 网络扩容 最大流+最小费用流

    题目链接:

    https://www.lydsy.com/JudgeOnline/problem.php?id=1834

    题目大意:

    给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。
    求: 
    1、在不扩容的情况下,1到N的最大流; 
    2、将1到N的最大流增加K所需的最小扩容费用。

    思路:

    第一问直接求费用流,第二问,在第一问的残余网络上,对于每条边额外加上INF容量费用为w的边,限制最大流量为k,也就是在0-1之间连边,容量为s,费用为0,然后跑一遍最小费用流就可以了。

      1 #include<bits/stdc++.h>
      2 #define IOS ios::sync_with_stdio(false);//不可再使用scanf printf
      3 #define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时
      4 #define Min(a, b) ((a) < (b) ? (a) : (b))
      5 #define Mem(a) memset(a, 0, sizeof(a))
      6 #define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1))
      7 #define MID(l, r) ((l) + ((r) - (l)) / 2)
      8 #define lson ((o)<<1)
      9 #define rson ((o)<<1|1)
     10 #define Accepted 0
     11 #pragma comment(linker, "/STACK:102400000,102400000")//栈外挂
     12 using namespace std;
     13 inline int read()
     14 {
     15     int x=0,f=1;char ch=getchar();
     16     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
     17     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     18     return x*f;
     19 }
     20 typedef long long ll;
     21 const int MOD = 1000000007;//const引用更快,宏定义也更快
     22 const double eps = 1e-10;
     23 const double pi = acos(-1);
     24 const int INF = 0x3f3f3f3f;
     25 const int maxn = 10000 + 10;
     26 struct edge
     27 {
     28     int u, v, c, f, cost;
     29     edge(int u, int v, int c, int f, int cost):u(u), v(v), c(c), f(f), cost(cost){}
     30 };
     31 vector<edge>e;
     32 vector<int>G[maxn];
     33 int a[maxn];//找增广路每个点的水流量
     34 int p[maxn];//每次找增广路反向记录路径
     35 int d[maxn];//SPFA算法的最短路
     36 int inq[maxn];//SPFA算法是否在队列中
     37 
     38 void addedge(int u, int v, int c, int cost)
     39 {
     40     e.push_back(edge(u, v, c, 0, cost));
     41     e.push_back(edge(v, u, 0, 0, -cost));
     42     int m = e.size();
     43     G[u].push_back(m - 2);
     44     G[v].push_back(m - 1);
     45 }
     46 bool bellman(int s, int t, int& flow, long long & cost)
     47 {
     48     for(int i = 0; i <= t + 1; i++)d[i] = INF;//Bellman算法的初始化
     49     memset(inq, 0, sizeof(inq));
     50     d[s] = 0;inq[s] = 1;//源点s的距离设为0,标记入队
     51     p[s] = 0;a[s] = INF;//源点流量为INF(和之前的最大流算法是一样的)
     52 
     53     queue<int>q;//Bellman算法和增广路算法同步进行,沿着最短路拓展增广路,得出的解一定是最小费用最大流
     54     q.push(s);
     55     while(!q.empty())
     56     {
     57         int u = q.front();
     58         q.pop();
     59         inq[u] = 0;//入队列标记删除
     60         for(int i = 0; i < G[u].size(); i++)
     61         {
     62             edge & now = e[G[u][i]];
     63             int v = now.v;
     64             if(now.c > now.f && d[v] > d[u] + now.cost)
     65                 //now.c > now.f表示这条路还未流满(和最大流一样)
     66                 //d[v] > d[u] + e.cost Bellman 算法中边的松弛
     67             {
     68                 d[v] = d[u] + now.cost;//Bellman 算法边的松弛
     69                 p[v] = G[u][i];//反向记录边的编号
     70                 a[v] = min(a[u], now.c - now.f);//到达v点的水量取决于边剩余的容量和u点的水量
     71                 if(!inq[v]){q.push(v);inq[v] = 1;}//Bellman 算法入队
     72             }
     73         }
     74     }
     75     if(d[t] == INF)return false;//找不到增广路
     76     flow += a[t];//最大流的值,此函数引用flow这个值,最后可以直接求出flow
     77     cost += (long long)d[t] * (long long)a[t];//距离乘上到达汇点的流量就是费用
     78     for(int u = t; u != s; u = e[p[u]].u)//逆向存边
     79     {
     80         e[p[u]].f += a[t];//正向边加上流量
     81         e[p[u] ^ 1].f -= a[t];//反向边减去流量 (和增广路算法一样)
     82     }
     83     return true;
     84 }
     85 int MincostMaxflow(int s, int t, long long & cost)
     86 {
     87     cost = 0;
     88     int flow = 0;
     89     while(bellman(s, t, flow, cost));//由于Bellman函数用的是引用,所以只要一直调用就可以求出flow和cost
     90     return flow;//返回最大流,cost引用可以直接返回最小费用
     91 }
     92 int u[maxn], v[maxn], c[maxn], w[maxn];
     93 int main()
     94 {
     95     IOS;
     96     int n, m, k;
     97     cin >> n >> m >> k;
     98     for(int i = 1; i <= m; i++)cin >> u[i] >> v[i] >> c[i] >> w[i];
     99     for(int i = 1; i <= m; i++)addedge(u[i], v[i], c[i], 0);
    100     ll cost;
    101     cout<<MincostMaxflow(1, n, cost)<<" ";
    102     addedge(0, 1, k, 0);
    103     addedge(n, n + 1, k, 0);
    104     for(int i = 1; i <= m; i++)addedge(u[i], v[i], INF, w[i]);
    105     MincostMaxflow(0, n + 1, cost);
    106     cout<<cost<<endl;
    107     return Accepted;
    108 }
  • 相关阅读:
    SP笔记:交叉实现七行并成一行
    HTML tag 学习
    操作哈希表
    Efficient bipedal robots based on passivedynamic walkers
    Pushing People Around
    ZEROMOMENT PONTTHIRTY FIVE YEARS OF ITS LIFE

    Active Learning for RealTime Motion Controllers
    Accelerometerbased User Interfaces for the Control of a Physically Simulated Character
    Dynamic Response for Motion Capture Animation
  • 原文地址:https://www.cnblogs.com/fzl194/p/9746239.html
Copyright © 2011-2022 走看看