题目地址:P4553 80人环游世界

上下界网络流

无源汇上下界可行流

给定 \(n\) 个点, \(m\) 条边的网络,求一个可行解,使得边 \((u,v)\) 的流量介于 \([B(u,v),C(u,v)]\) 之间,并且整个网络满足流量守恒。

如果把 \(C-B\) 作为容量上界, \(0\) 作为容量下界,就是一般的网络流模型。

然而求出的实际流量为 \(f(u,v)+B(u,v)\) ,不一定满足流量守恒,需要调整。

设 \(inB[u]=\sum B(i,u)\) , \(outB[u]=\sum B(u,i)\) , \(d[u]=inB[u]-outB[u]\) 。

新建源汇, \(S\) 向 \(d>0\) 的点连边, \(d<0\) 的点向 \(T\) 连边,容量为相应的 \(d\) 。

在该网络上求最大流,则每条边的流量 \(+\) 下界就是原网络的一个可行流。

具体实现时,可省略 \(inB,outB\) 数组,直接在 \(d\) 数组上修改。

有源汇上下界可行流

从 \(T\) 到 \(S\) 连一条下界为 \(0\) ,上界为 \(+inf\) 的边,把汇流入的流量转移给源流出的流量,转化为无源汇的网络,然后求解无源汇上下界可行流

有源汇上下界最小费用可行流

类似有源汇上下界可行流,求最大流改为求最小费用最大流。

每个国家拆成两个点(入点 \(i\) 和出点 \(i+n\)),建立源 \(s\) 汇 \(t\) 附加源 \(s\_\) 。

连边:

  1. \((s,s\_,m,m,0)\) ;
  2. \((s\_,i,0,m,0)\) ;
  3. \((i+n,t,0,m,0)\) ;
  4. \((i,i+n,V[i],V[i],0)\) ;
  5. 若 \(i,j\) 两个国家通航,连边 \((i+n,j,0,m,Cost_{i,j})\) 。

对网络 \(s-t\) 求有源汇上下界最小费用可行流

#include <bits/stdc++.h>
using namespace std;
const int N = 206, M = 1e5 + 6, inf = 0x3f3f3f3f;
int n, m, S, T, s, s_, t, d[N], now[N], pre[N], ans;
int Head[N], Edge[M], Leng[M], Cost[M], Next[M], tot = 1;
bitset<N> v;

inline void add(int x, int y, int z, int w) {
    Edge[++tot] = y;
    Leng[tot] = z;
    Cost[tot] = w;
    Next[tot] = Head[x];
    Head[x] = tot;
    Edge[++tot] = x;
    Leng[tot] = 0;
    Cost[tot] = -w;
    Next[tot] = Head[y];
    Head[y] = tot;
}

inline void ins(int x, int y, int l, int r, int w) {
    add(x, y, r - l, w);
    d[x] -= l;
    d[y] += l;
}

inline bool spfa() {
    v.reset();
    memset(d, 0x3f, sizeof(d));
    queue<int> q;
    q.push(S);
    v[S] = 1;
    d[S] = 0;
    now[S] = m;
    while (q.size()) {
        int x = q.front();
        q.pop();
        v[x] = 0;
        for (int i = Head[x]; i; i = Next[i]) {
            int y = Edge[i], z = Leng[i], w = Cost[i];
            if (!z || d[y] <= d[x] + w) continue;
            d[y] = d[x] + w;
            now[y] = min(now[x], z);
            pre[y] = i;
            if (!v[y]) {
                q.push(y);
                v[y] = 1;
            }
        }
    }
    return d[T] != inf;
}

inline void upd() {
    ans += d[T] * now[T];
    int x = T;
    while (x != S) {
        int i = pre[x];
        Leng[i] -= now[T];
        Leng[i^1] += now[T];
        x = Edge[i^1];
    }
}

int main() {
    cin >> n >> m;
    s = n * 2 + 1, s_ = s + 1, t = s_ + 1;
    S = t + 1, T = S + 1;
    ins(s, s_, m, m, 0);
    for (int i = 1; i <= n; i++) {
        ins(s_, i, 0, m, 0);
        ins(i + n, t, 0, m, 0);
        int x;
        scanf("%d", &x);
        ins(i, i + n, x, x, 0);
    }
    for (int i = 1; i <= n; i++)
        for (int j = i + 1; j <= n; j++) {
            int x;
            scanf("%d", &x);
            if (~x) ins(i + n, j, 0, m, x);
        }
//  ins(t, s, 0, m, 0);
    for (int i = 1; i <= t; i++) {
        if (d[i] > 0) add(S, i, d[i], 0);
        else if (d[i] < 0) add(i, T, -d[i], 0);
    }
    while (spfa()) upd();
    cout << ans << endl;
    return 0;
}

注意:代码中注释的那一条语句加不加都可以AC,具体原因有待研究(讨论

P4553 80人环游世界的更多相关文章

  1. P4553 80人环游世界(上下界费用流)

    P4553 80人环游世界 emm......先从上下界网络流(转)开始 再到现在的上下界费用流 因为有上下界,我们需要记下每个点的流量差$ex[i]$,用于调整 $ins(x,y,l,r,v)=li ...

  2. 洛谷P4553 80人环游世界

    题目描述 https://www.luogu.org/problemnew/show/P4553 题解 思路比较显然,把图建出来,一个国家拆成两个点,中间设置上下界,然后跑费用流. 我把源那边的流量也 ...

  3. Luogu P4553 80人环游世界

    link 题目大意 自东向西有 \(n\) 个国家.有 \(m\) 个人,他们可以选择 \(n\) 个国家中任意一个开始,任意一个结束,但路线必须自东向西,且第 \(i\) 个国家必须恰好经过 \(v ...

  4. 【BZOJ-2055】80人环游世界 上下界费用流 (无源无汇最小费用最大流)

    2055: 80人环游世界 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 321  Solved: 201[Submit][Status][Discus ...

  5. BZOJ2055: 80人环游世界

    题解: 总算A掉了,各种蛋疼... int main() { freopen("input.txt","r",stdin); freopen("out ...

  6. BZOJ 2055: 80人环游世界 [上下界费用流]

    2055: 80人环游世界 题意:n个点带权图,选出m条路径,每个点经过val[i]次,求最小花费 建图比较简单 s拆点限制流量m 一个点拆成两个,限制流量val[i],需要用上下界 图中有边的连边, ...

  7. [BZOJ2055]80人环游世界 有上下界最小费用最大流

    2055: 80人环游世界 Time Limit: 10 Sec  Memory Limit: 64 MB Description     想必大家都看过成龙大哥的<80天环游世界>,里面 ...

  8. bzoj 2055: 80人环游世界 -- 上下界网络流

    2055: 80人环游世界 Time Limit: 10 Sec  Memory Limit: 64 MB Description     想必大家都看过成龙大哥的<80天环游世界>,里面 ...

  9. 【BZOJ】2055 80人环游世界

    [算法]有源汇上下界最小费用可行流 [题解]上下界 因为上下界相同,所以无所谓最小流了,可行流(初始流+附加流)就是答案了. 记得源点向新建节点连一条容量为m(人)的边. bzoj 2055 80人环 ...

随机推荐

  1. Collection中的迭代器

    迭代器:boolean hasNext() 判断集合中是否还有没有被取出数据nexe() 取出集合中下一个元素package cn.lijun.demo4; import java.util.Arra ...

  2. 关键字(2):循环和分支结构for/while/loop/switch

    FOR i IN tRange1.first .. tRange1.last LOOP IF Instr(CardNum, tRange1(i), ) = THEN GLOBAL_VARBLE.nPo ...

  3. es6基础知识总结(附加)

    附加: 字符串扩展: 1. includes(str) : 判断是否包含指定的字符串2. startsWith(str) : 判断是否以指定字符串开头3. endsWith(str) : 判断是否以指 ...

  4. python对象继承

    继承允许我们在两个或者更多的类之间创建一种“是一个”的关系,这种关系把共同的细节抽象到一个超类里. 从技术上讲,每一个我们创建的类都使用了继承,所有的python类都是一个叫做object的特殊类的子 ...

  5. ARM三级流水线

    title: ARM三级流水线 tags: ARM date: 2018-10-14 16:57:10 --- 参考: ARM指令集E004armproc.chm ARM Architecture R ...

  6. 实战Google深度学习框架-C5-MNIST数字识别问题

    5.1 MNIST数据处理 MNIST是NIST数据集的一个子集,包含60000张图片作为训练数据,10000张作为测试数据,其中每张图片代表0~9中的一个数字,图片大小为28*28(可以用一个28* ...

  7. JAVA-Proxy 代理

    jdk静态代理 interface Dao { void save(); } class DaoImpl implements Dao { @Override public void save() { ...

  8. spring-data-redis集成ehcache实现缓存

    1.结构 2.pom.xml <?xml version="1.0" encoding="UTF-8"?><project xmlns=&qu ...

  9. C语言宏定义##连接符和#符的使用

    1. 关于宏(Macro) 属于编译器预处理的范畴,属于编译器概念(而非运行期概念). 2. 关于# #的功能:是 将其后面的宏参数进行 字符串化操作(Stringfication),即:在对它所引用 ...

  10. Jsp的四大作用域与九大对象

    内置对象特点: 1. 由JSP规范提供,不用编写者实例化. 2. 通过Web容器实现和管理 3. 所有JSP页面均可使用 4. 只有在脚本元素的表达式或代码段中才可使用(<%=使用内置对象%&g ...