1. 程式人生 > >[bzoj2055] 80人環遊世界

[bzoj2055] 80人環遊世界

時間 spf head 表示 bits cap 吸引力 沒有 isp

Description

想必大家都看過成龍大哥的《 \(80\) 天環遊世界》,裏面的緊張刺激的打鬥場面一定給你留下了深刻的印象。現在就有這麽

一個 \(80\) 人的團夥,也想來一次環遊世界。

他們打算兵分多路,遊遍每一個國家。

因為他們主要分布在東方,所以他們只朝西方進軍。設從東方到西方的每一個國家的編號依次為 \(1\cdots N\) 。假若第i個人的遊歷路線為 \(P_1,P_2\cdots P_k(0\le k\le N)\),則 \(P_1<P_2<\cdots <P_k\)

眾所周知,中國相當美麗,這樣在環遊世界時就有很多人經過中國。我們用一個正整數 \(V_i\)

來描述一個國家的吸引程度,Vi值越大表示該國家越有吸引力,同時也表示有且僅有 \(V_i\) 個人會經過那一個國家。

為了節省時間,他們打算通過坐飛機來完成環遊世界的任務。同時為了省錢,他們希望總的機票費最小。

明天就要出發了,可是有些人臨陣脫逃,最終只剩下了 \(M\) 個人去環遊世界。他們想知道最少的總費用,你能告訴他們嗎?

Input

第一行兩個正整數 \(N,M\)

第二行有 \(N\) 個不大於 \(M\) 正整數,分別表示 \(V_1,V_2\cdots V_N\)

接下來有 \(N-1\) 行。第 \(i\) 行有 \(N -i\) 個整數,該行的第 \(j\) 個數表示從第 \(i\)

個國家到第 \(i+j\) 個國家的機票費(如果該值等於 \(-1\) 則表示這兩個國家間沒有通航)。

Output

在第一行輸出最少的總費用。

Sample Input

6 3
2 1 3 1 2 1
2 6 8 5 0
8 2 4 1
6 1 0
4 -1
4

Sample Output

27

HINT

\(1\le N \le 100,1\le M \le 79\)

Solution

技術分享圖片
技術分享圖片
技術分享圖片
這大概就是題面欽定數據範圍吧...

這是一道上下界費用流。

將國家 \(x\) 拆成入點 \(x_1\) ,出點 \(x_2\) ,同時建源點 \(S\) ,匯點 \(T\) ,第二源點 \(SS\)

首先 \[<S, SS>:capacity=m,cost=0\]

對於國家 \(x\) \[<SS,x_1>:capacity=INF,cost = 0\] \[<x_2,T>:capacity=INF,cost=0\] \[<x_1,x_2>:capacity=[V, V],cost=0\]

如果 \(x\)\(y\) 有航線,則 \[<x_2,y_1>:capacity=INF,cost=W\]

然後跑一個上下界費用流即可。具體做法是先把每條邊的 \(lw\) 乘上 \(cost\) 加到答案裏(當然本題不需要),再跑一個普通的費用流。

#include<bits/stdc++.h>
using namespace std;

#define N 1001
#define INF 2000000000
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define ll long long

inline int read() {
    int x = 0, flag = 1; char ch = getchar(); while (!isdigit(ch)) { if (!(ch ^ '-')) flag = -1; ch = getchar(); }
    while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x * flag;
}

int n, m, SS, SSS, TT;
int du[N];

int S, T, flow, cost;
struct edge { int u, v, c, w, next; }e[20001];
int head[N], tot = 1;
int dis[N], pre[N];
queue<int> q;
bool inq[N];
inline void insert(int u, int v, int c, int w) { e[++tot].u = u, e[tot].v = v, e[tot].c = c, e[tot].w = w, e[tot].next = head[u], head[u] = tot; }
inline void add(int u, int v, int c, int w) { insert(u, v, c, w), insert(v, u, 0, -w); }
inline bool spfa() {
    rep(i, S, T) dis[i] = INF; dis[S] = 0; q.push(S);
    while (!q.empty()) {
        int u = q.front(); q.pop(); inq[u] = 0;
        for (int i = head[u], v, w; i; i = e[i].next) if (e[i].c > 0 && dis[v = e[i].v] > dis[u] + (w = e[i].w)) {
            dis[v] = dis[u] + w, pre[v] = i;
            if (!inq[v]) q.push(v); inq[v] = 1;
        }
    }
    return dis[T] != INF;
}
inline void mcf() {
    int d = INF;
    for (int i = T; (i ^ S); i = e[pre[i]].u) d = min(d, e[pre[i]].c);
    flow += d;
    for (int i = T; (i ^ S); i = e[pre[i]].u) e[pre[i]].c -= d, e[pre[i] ^ 1].c += d, cost += d * e[pre[i]].w;
}

int main() {
    cin >> n >> m; SSS = 2 * n + 1, SS = SSS + 1, TT = SS + 1, T = TT + 1;
    rep(i, 1, n) {
        add(SSS, i, INF, 0), add(i + n, TT, INF, 0);
        int V = read(); add(i, i + n, 0, 0);
        du[i] -= V, du[i + n] += V;
    }
    add(SS, SSS, m, 0);
    rep(i, 1, n) rep(j, i + 1, n) { int V = read(); if(V != -1) add(i + n, j, INF, V); }
    add(TT, SS, INF, 0);
    rep(i, 1, TT) if (du[i] > 0) add(S, i, du[i], 0); else add(i, T, -du[i], 0);
    while (spfa()) mcf(); cout << cost;
    return 0;
}

[bzoj2055] 80人環遊世界