zoukankan      html  css  js  c++  java
  • [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;
    }
    
    
  • 相关阅读:
    SGU 271 Book Pile (双端队列)
    POJ 3110 Jenny's First Exam (贪心)
    HDU 4310 Hero (贪心)
    ZOJ 2132 The Most Frequent Number (贪心)
    POJ 3388 Japanese Puzzle (二分)
    UVaLive 4628 Jack's socks (贪心)
    POJ 2433 Landscaping (贪心)
    CodeForces 946D Timetable (DP)
    Android Studio教程从入门到精通
    Android Tips – 填坑手册
  • 原文地址:https://www.cnblogs.com/mollnn/p/13161466.html
Copyright © 2011-2022 走看看