[bzoj2055] 80人环游世界

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;
}
posted @ 2018-02-11 23:01  aziint  阅读(186)  评论(0编辑  收藏  举报
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.