有下届最小费用可行流模板

传送门

题目描述:有一个树形的通关图,通过每个关卡需要一定的时间,随时可以停止回到起点重新开始游戏,

问把所有关卡都玩一遍的最少时间

思路:下届为1的最小费用流模板

模板代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
int inf = 1e9 + 7;
using namespace std;
inline int read() {
    int re = 0, flag = 1; char ch = getchar();
    while (ch > '9' || ch < '0') {
        if (ch == '-') flag = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') re = (re << 1) + (re << 3) + ch - '0', ch = getchar();
    return re * flag;
}
int n, ans, first[510], cnt = -1;
int dis[510], vis[510], q[20010], head, tail;
struct edge {
    int to, next, w, cap;
}a[100010];
inline void add(int u, int v, int w, int cap) {
    a[++cnt] = (edge){ v,first[u],w,cap }; first[u] = cnt;
    a[++cnt] = (edge){ u,first[v],-w,0 }; first[v] = cnt;
}
bool spfa(int s, int t) {
    int i, u, v, w; head = 0, tail = 1;
    memset(dis, -1, sizeof(dis)); memset(vis, 0, sizeof(vis));
    q[0] = t; dis[t] = 0; vis[t] = 1;
    while (head < tail) {
        u = q[head++]; vis[u] = 0;
        for (i = first[u]; ~i; i = a[i].next) {
            if (!a[i ^ 1].cap) continue;
            v = a[i].to; w = a[i].w;
            if (dis[v] == -1 || dis[v] > dis[u] - w) {
                dis[v] = dis[u] - w;
                if (!vis[v]) {
                    vis[v] = 1, q[tail++] = v;
                }
            }
        }
    }
    return ~dis[s];
}
int dfs(int u, int t, int limit) {
    if (u == t) { vis[t] = 1; return limit; }
    int i, v, f, flow = 0; vis[u] = 1;
    for (i = first[u]; ~i; i = a[i].next) {
        v = a[i].to;
        if ((dis[v] == dis[u] - a[i].w) && (a[i].cap) && (!vis[v])) {
            f = dfs(v, t, min(limit, a[i].cap));
            if (f) {
                flow += f; limit -= f;
                ans += f * a[i].w;
                a[i].cap -= f; a[i ^ 1].cap += f;
                if (!limit) return flow;
            }
        }
    }
    return flow;
}
int dinic(int s, int t) {//我写的是从某博客上学的改进版zkw费用流
    int re = 0;
    while (spfa(s, t)) {
        vis[t] = 1;
        while (vis[t]) {
            memset(vis, 0, sizeof(vis));
            re += dfs(s, t, inf);
        }
    }
    return re;
}
int d[510];
int main() {
    memset(first, -1, sizeof(first));
    n = read(); int i, t1, t2, t3, j;
    for (i = 1; i <= n; i++) {
        t1 = read();
        for (j = 1; j <= t1; j++) {
            t2 = read(); t3 = read();
            d[i]--; d[t2]++;//流量下界其实都是一 
            ans += t3;//加上下届的费用
            add(i, t2, t3, inf);
        }
    }
    for (i = 2; i <= n; i++) {//随时可以结束,回到起点
        add(i, n + 1, 0, inf);
    }
    for (i = 1; i <= n; i++) {//补流过程
        if (d[i] > 0) add(0, i, 0, d[i]);
        if (d[i] < 0) add(i, n + 2, 0, -d[i]);
    }
    add(n + 1, 1, 0, inf);
    dinic(0, n + 2);//最小费用可行流
    cout << ans << endl;
}

 

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