• bzoj3876 [Ahoi2014]支线剧情


    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3876

    【题解】

    一眼看过去好像就是一个网络流啊

    那怎么建图呢

    首先图上的边看作下界为1,上界inf的边,费用为给定的费用。

    每个点都可以回到起点(1)开始下一次的观看,所以每个点到1连下界为0,上界inf的边,费用为0.

    这是一个“无源汇,有上下界,最小费用可行流”问题。

    我们先按照有上下界的处理方法,将每条边上下界统一成上界,然后S连到入度为正,入度为负连到T,费用均为0,流量为度数绝对值。

    这样我们建造的网络就可以得出每条边都选了下界时,还需要选择多少能够满足条件。

    那么把每条边下界乘费用加进去即可。

    注意一定要把S->x和x->T的整合一起连。

    看了一眼以前某学长没整合跑了9s,我整合完跑了100ms..

    # include <queue>
    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 3e5 + 10;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    int n;
    
    int S, T, d[M];
    int head[M], nxt[M], to[M], flow[M], w[M], tot=1;
    inline void add(int u, int v, int fl, int _w) {
        ++tot; nxt[tot] = head[u]; head[u] = tot;
        to[tot] = v; flow[tot] = fl; w[tot] = _w;
    }
    inline void adde(int u, int v, int fl, int _w) {
    //    printf("%d->%d, %d, cost = %d
    ", u, v, fl, _w);
        add(u, v, fl, _w);
        add(v, u, 0, -_w);
    }
    
    namespace MCF {
        queue<int> q;
        int dis[M], pre[M];
        bool vis[M];
        inline bool spfa() {
            while(!q.empty()) q.pop();
            for (int i=1; i<=n+2; ++i) vis[i] = 0, dis[i] = 1e9, pre[i] = 0;
            q.push(S); vis[S] = 1; dis[S] = 0;
            while(!q.empty()) {
                int top = q.front(); q.pop(); vis[top] = 0;
                for (int i=head[top]; i; i=nxt[i]) {
                    if(flow[i] && dis[to[i]] > dis[top] + w[i]) {
                        dis[to[i]] = dis[top] + w[i];
                        pre[to[i]] = i;
                        if(!vis[to[i]]) {
                            vis[to[i]] = 1;
                            q.push(to[i]);
                        }
                    }
                }
            }
    //        for (int i=1; i<=n+2; ++i) cout << i << ' ' << d[i] << endl;
    //        puts("");
            return dis[T] != 1e9;
        }
        inline int mcf() {
            int fl = 1e9, ans = 0;
            for (int i=pre[T]; i; i=pre[to[i^1]])
                fl = min(fl, flow[i]);
            for (int i=pre[T]; i; i=pre[to[i^1]]) {
                flow[i] -= fl;
                flow[i^1] += fl;
                ans += fl * w[i];
            }
            return ans;
        }
        inline int main() {
            int ret = 0;
            while(spfa()) ret += mcf();
            return ret;
        }
    }
    
    int main() {
        int ans = 0;
        cin >> n;
        S = n+1, T = n+2;
        for (int i=1, m, Bi, Ti; i<=n; ++i) {
            scanf("%d", &m);
            for (int j=1; j<=m; ++j) {
                scanf("%d%d", &Bi, &Ti);
                adde(i, Bi, 1e9, Ti);
                d[Bi] ++; d[i] --; ans += Ti;
            }
            if(i != 1) adde(i, 1, 1e9, 0);
        }
        
        for (int i=1; i<=n; ++i) {
            if(d[i] > 0) adde(S, i, d[i], 0);
            if(d[i] < 0) adde(i, T, -d[i], 0);
        }
        
        cout << MCF::main() + ans << endl;
    
        return 0;
    }
    View Code
  • 相关阅读:
    BZOJ 1050 旅行
    BZOJ 1040 骑士
    BZOJ 1038 瞭望塔
    BZOJ 1037 生日聚会
    BZOJ 1823 满汉全席
    BZOJ 3091 城市旅行
    CF702E Analysis of Pathes in Functional Graph
    Luogu 2154 [SDOI2009]虔诚的墓主人
    Luogu 1268 树的重量
    Luogu 4867 Gty的二逼妹子序列
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj3876.html
Copyright © 2020-2023  润新知