• [AHOI2014/JSOI2014] 支线剧情


    Description

    给一张有向无环图,每次你可以选择一条从 (1) 号点出发的路径走,花费的时间为路径上边权的总和,问要使所有边都被走至少一遍,至少需要花费多久。

    Solution

    DAG 上的可重复定源路径覆盖,考虑有上下界网络流模型

    对题意中的每个点建点,对于题意中的每条边,在建图时,费用为边权,容量下界为 (1),上界为 (+infty)

    (1) 当源点,每个非源的点向 (T) 连边,容量不限制,费用为 (0)

    在这个图上跑有源汇有上下界费用流

    建立超级源点 (S') 和超级源点 (T'),对于所有原有点,对其下界,设 (d[p]=p) 的输入量 (- p) 的输出量,若 (d[p]>0) 则由 (S')(p) 连边,费用为 (0),容量为 (|d[p]|);若 (d[p]<0) 则由 (p)(T') 连边,,费用为 (0),容量为 (|d[p]|);否则不连边

    原图中的汇点向原图中的源点连边,容量不限制,费用为 (0)

    其它所有边的容量设为上界减去下界

    在此基础上,跑最小费用最大流,得到的费用加上所有下界的费用就是答案

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    // Init: init() !!!!!
    // Input: make(u,v,cap,cost)
    // Solver: solve(s,t)
    // Output: ans, cost
    const int inf = 1e+12;
    namespace flow {
        const int N = 100005;
        const int M = 1000005;
    
        struct Edge {
            int p, c, w, nxt = -1;
        } e[N];
        int s, t, tans, ans, cost, ind, bus[N], qhead = 0, qtail = -1, qu[M],vis[N], dist[N];
    
        void graph_link(int p, int q, int c, int w) {
            e[ind].p = q;
            e[ind].c = c;
            e[ind].w = w;
            e[ind].nxt = bus[p];
            bus[p] = ind;
            ++ind;
        }
        void make(int p, int q, int c, int w) {
            //cout<<p<<" "<<q<<" "<<c<<endl;
            graph_link(p, q, c, w);
            graph_link(q, p, 0, -w);
        }
        int dinic_spfa() {
            qhead = 0;
            qtail = -1;
            memset(vis, 0x00, sizeof vis);
            memset(dist, 0x3f, sizeof dist);
            vis[s] = 1;
            dist[s] = 0;
            qu[++qtail] = s;
            while (qtail >= qhead) {
                int p = qu[qhead++];
                vis[p] = 0;
                for (int i = bus[p]; i != -1; i = e[i].nxt)
                    if (dist[e[i].p] > dist[p] + e[i].w && e[i].c > 0) {
                        dist[e[i].p] = dist[p] + e[i].w;
                        if (vis[e[i].p] == 0)
                            vis[e[i].p] = 1, qu[++qtail] = e[i].p;
                    }
            }
            return dist[t] < inf;
        }
        int dinic_dfs(int p, int lim) {
            if (p == t)
                return lim;
            vis[p] = 1;
            int ret = 0;
            for (int i = bus[p]; i != -1; i = e[i].nxt) {
                int q = e[i].p;
                if (e[i].c > 0 && dist[q] == dist[p] + e[i].w && vis[q] == 0) {
                    int res = dinic_dfs(q, min(lim, e[i].c));
                    cost += res * e[i].w;
                    e[i].c -= res;
                    e[i ^ 1].c += res;
                    ret += res;
                    lim -= res;
                    if (lim == 0)
                        break;
                }
            }
            return ret;
        }
        void solve(int _s,int _t) {
            s=_s; t=_t;
            while (dinic_spfa()) {
                memset(vis, 0x00, sizeof vis);
                ans += dinic_dfs(s, inf);
            }
        }
        void init() {
            memset(bus, 0xff, sizeof bus);
        }
    }
    
    namespace limflow {
        struct edge {
            int u,v,l,r,c;
        };
        vector <edge> vec;
        const int N = 100005;
        int ans,cost,d[N];
        void make(int u,int v,int l,int r,int c) {
            vec.push_back({u,v,l,r,c});
        }
        void solve(int s,int t) {
            ans=0;
            cost=0;
            flow::init();
            int mx=0;
            for(edge e:vec) {
                mx=max(mx,max(e.u,e.v));
                d[e.v]+=e.l;
                d[e.u]-=e.l;
                flow::make(e.u,e.v,e.r-e.l,e.c);
                cost+=e.c*e.l;
            }
            flow::make(t,s,inf,0);
            for(int i=1;i<=mx;i++) {
                if(d[i]>0) {
                    flow::make(mx+1,i,abs(d[i]),0);
                }
                if(d[i]<0) {
                    flow::make(i,mx+2,abs(d[i]),0);
                }
            }
            flow::solve(mx+1,mx+2);
            ans=flow::ans;
            cost+=flow::cost;
        }
    }
    
    using limflow::make;
    using limflow::solve;
    using limflow::cost;
    
    const int N = 100005;
    int deg[N];
    
    signed main() {
        ios::sync_with_stdio(false);
        int n,k,t1,t2;
        cin>>n;
        for(int i=1;i<=n;i++) {
            cin>>k;
            while(k--) {
                cin>>t1>>t2;
                deg[i]++;
                make(i,t1,1,inf,t2);
            }
        }
        for(int i=2;i<=n;i++) {
            if(deg[i]==0) {
                make(i,n+1,0,inf,0);
            }
        }
        solve(1,n+1);
        cout<<cost;
    }
    
    
  • 相关阅读:
    常用模块的作业
    一些常用的模块
    软件开发的目录规范

    匿名函数作业
    模块
    算法,面向过程与匿名函数
    生成器表达式作业
    C. Perfect Keyboard
    C. Ehab and Path-etic MEXs
  • 原文地址:https://www.cnblogs.com/mollnn/p/13161466.html
Copyright © 2020-2023  润新知