有汇源上下界最大流模板

传送门

题目描述:

在接下来的n天中,射命丸文将要拍摄幻想乡的少女的照片并且从中为第x个少女拍摄至少Gx张照片刊登在《文文。新闻》上。在第k天的时候文文有Ck个取材对象,且对于每个取材对象拍的照片必须在闭区间[Lki,Rki]中。如果过少,

文文就搞不出大新文;如果过多,就会有少女很安格瑞。除此之外,因为拍照设备的原因,对于第i天,每天的拍照数量不能超过Di张。在满足这些限定的条件下,文文希望拍到的照片尽可能地多。

由于文文需要去取材,因此她把这个任务交给了你,让你帮她去解决。

思路:模板题,把n天和少女看成节点,源点对每天连边,容量为Di,每天再与可以拍照的少女连边,容量为up-down,每个少女至少要拍Gx张照片,少女要对汇点连容量为INT-Gx的边,这里还没理解到,

汇点再对源点连水泵边(容量为inf),上述连边的同时要求出imo[i],即每个点的所连边的流入流量-流出流量,再建立新的源点和汇点,然后按照无汇源上下界可行流的连边方法,求出最大可行流,

如果最大可行流是等于新源点的所有出边的流量总和,说明少女的最少照片Gx得到了满足,然后再删除水泵边,跟换为最初的源点和汇点,把剩余残存流量榨干,与最大可行流相加就得到了最大流。

code:

int n, m, s1, t1;
int imo[maxn];//入边流量-出边流量
int main() {
    while (~scanf("%d%d", &n, &m)) {
        memset(hd, 0, sizeof(hd)); tot = 1;
        memset(imo, 0, sizeof(imo));
        s1 = n + m + 1, t1 = s1 + 1;
        s = t1 + 1, t = s + 1;
        for (int i = n+1; i <= n+m; i++) {
            int g; scanf("%d", &g);
            add(i, t1, inf - g);
            imo[i] -= g;
            imo[t1] += g;
        }
        for (int i = 1; i <= n; i++) {
            int c, d; scanf("%d%d", &c, &d);
            add(s1, i, d);
            while (c--) {
                int a, l, r; scanf("%d%d%d", &a, &l, &r);
                a++;
                add(i, a + n, r - l);
                imo[i] -= l;//注意这里是下届
                imo[a + n] += l;
            }
        }
        int cnt = 0;
        for (int i = 1; i <= n + m + 2; i++) {
            if (imo[i] > 0) {
                add(s, i, imo[i]); cnt+=imo[i];
            }
            else {
                add(i, t, -imo[i]);
            }
        }
        add(t1, s1, inf);//水泵
        if (dinic()!= cnt) {//判断少女的最少拍照数得到满足
            printf("-1\n\n");
        }
        else {
            s = s1, t = t1;//更换源点汇点
            int res = e[tot].flow;//反向边就是s1->t1的可行最大流
            e[tot].flow = 0; e[tot - 1].flow = 0;//去掉水泵边
            printf("%lld\n\n", dinic() + res);//榨干残留网络
        }
    }
    return 0;
}

 

posted @ 2021-05-21 12:05  cono奇犽哒  阅读(49)  评论(0编辑  收藏  举报