bzoj2055 80人环游世界

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

【题解】

跟上一题(支线剧情)很像,与上题不同是这题看作求“最大流”(我们限制过流量了),上一题是求“可行流”无源汇的做法。

我们考虑先建出带有上下界的网络流:

S1->S2 [m,m] cost = 0

out(i)->in(j) [0, inf] cost = p[i][j]

in(i)->out(i) [vi, vi] cost = 0;

out(i)->T [0, inf] cost = 0

注意p[i][j]=-1不要建边

那么这样过后,直接按照通常转成非下界限制的费用流做就行了

因为这题有源汇,所以不需要提前算答案

# 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 = 5e5 + 10, N = 210;
const int mod = 1e9+7;

# define RG register
# define ST static

int n, m, S, T;
int p[N][N], V[N], d[N];

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) {
    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+n+5; ++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]);
                    }
                }
            }
        }
        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;
    }
}

inline void ADD(int u, int v, int fll, int flr, int _w) {
    adde(u, v, flr-fll, _w);
    d[v] += fll; d[u] -= fll;
}

int main() {
    cin >> n >> m;
    for (int i=1; i<=n; ++i) scanf("%d", &V[i]);
    for (int i=1; i<=n; ++i)
        for (int j=i+1; j<=n; ++j) scanf("%d", &p[i][j]);
    
    int S1 = n+n+1, S2 = n+n+2, T0 = n+n+3;
    
    for (int i=1; i<=n; ++i) ADD(i, i+n, V[i], V[i], 0);
    for (int i=1; i<=n; ++i)
        for (int j=i+1; j<=n; ++j)
            if(p[i][j] != -1) ADD(i+n, j, 0, 1e9, p[i][j]);
    
    ADD(S1, S2, m, m, 0);
    for (int i=1; i<=n; ++i) ADD(S2, i, 0, 1e9, 0);
    for (int i=1; i<=n; ++i) ADD(i+n, T0, 0, 1e9, 0);
    
    S = n+n+4, T = n+n+5;
    for (int i=1; i<=n+n+3; ++i) {
        if(d[i] > 0) adde(S, i, d[i], 0);
        if(d[i] < 0) adde(i, T, -d[i], 0);
    }
    
    cout << MCF::main() << endl;
    
    return 0;
}
View Code

 

posted @ 2017-05-29 17:32  Galaxies  阅读(284)  评论(0编辑  收藏  举报