bzoj4873[SHOI2017]寿司餐厅(最大权闭合子图、最小割)

题目链接

BZOJ

洛谷

解析

\(dalao\)一看这题就知道是个最大权闭合子图

然而蒟蒻我看了题解才知道

然后一搜才知道以前写过的某些最小割叫最大权闭合子图,原来是有套路的……

首先观察题目,发现如果收益中有\(d_{i,j}\),那么也一定有\(d_{i - 1, j}\)\(d_{i, j - 1}\),因为每次选择只能是连续区间

我们给每个区间\([i, j]\)建一个点,它的权值为\(d_{i, j}\),并从它向\([i + 1, j]\)\([i, j - 1]\)两个点连边,表示选了\([i, j]\)就必须选\([i + 1, j]\)\([i, j - 1]\)

每个代号\(x\)的花费可以拆成两部分:\(mx^2\)\(cx\)

前一部分只和这个代号选没选有关,所以每个代号建一个点,权值为\(-mx^2\),每个\([i, i]\)向它的代号\(a[i]\)连边,表示选了\(i\)就必选它的代号

后一部分和选的寿司种类有关,假设选了\([i, i]\),那么会增加\(a[i]\)的花费,所以可以把\([i, i]\)这个点的权值减去\(a[i]\)

上面建出的是原图,然后按最大权闭合子图的套路转化成最小割即可,这里就不写怎么转化了……

P.S.

题面巨长,变量的关系需要好好捋一捋……

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#define id(x, y) (((x) - 1) * N + (y))

typedef long long LL;
const int inf = 0x3f3f3f3f;
struct Graph {
	struct Edge {
		int v, next, cap;
		Edge(int _v = 0, int _n = 0, int _c = 0):v(_v), next(_n), cap(_c) {}
	};
	std::vector<Edge> edge;
	int cnt, head[11500], cur[11500], dep[11500];
	void init() { memset(head, -1, sizeof head); cnt = 0; }
	void add_edge(int u, int v, int c) { edge.push_back(Edge(v, head[u], c)); head[u] = edge.size() - 1; }
	void insert(int u, int v, int c) { add_edge(u, v, c); add_edge(v, u, 0); }
	bool bfs();
	int dfs(int, int);
	int Dinic();
} G;
int a[105], d[105][105];
int N, M, ans;

int main() {
	G.init();
	std::ios::sync_with_stdio(false);
	std::cin >> N >> M;
	for (int i = 1; i <= N; ++i) std::cin >> a[i];
	for (int i = 1; i <= N; ++i) for (int j = i; j <= N; ++j) std::cin >> d[i][j];
	for (int i = 1; i <= N; ++i) for (int j = i + 1; j <= N; ++j) { G.insert(id(i, j), id(i, j - 1), inf); G.insert(id(i, j), id(i + 1, j), inf); }
	for (int i = 1; i <= N; ++i) G.insert(id(i, i), id(N, N) + a[i], inf);
	for (int i = 1; i <= 1000; ++i) G.insert(id(N, N) + i, id(N, N) + 1001, M * i * i);
	for (int i = 1; i <= N; ++i) G.insert(id(i, i), id(N, N) + 1001, a[i]);
	for (int i = 1; i <= N; ++i) for (int j = i; j <= N; ++j)
		if (d[i][j] > 0) G.insert(0, id(i, j), d[i][j]), ans += d[i][j];
		else if (d[i][j] < 0) G.insert(id(i, j), id(N, N) + 1001, -d[i][j]);
	std::cout << ans - G.Dinic() << std::endl;

	return 0;
}
bool Graph::bfs() {
	int que[11500], hd = 0, tl = 1;
	memset(dep, -1, sizeof dep);
	que[0] = dep[0] = 0;
	while (hd < tl) {
		int p = que[hd++];
		for (int i = head[p]; ~i; i = edge[i].next)
			if (edge[i].cap && !(~dep[edge[i].v])) {
				dep[edge[i].v] = dep[p] + 1;
				que[tl++] = edge[i].v;
			}
	}
	return ~dep[id(N, N) + 1001];
}
int Graph::dfs(int u, int max_flow) {
	if (u == id(N, N) + 1001) return max_flow;
	int res = 0;
	for (int &i = cur[u]; ~i; i = edge[i].next)
		if (edge[i].cap && dep[edge[i].v] == dep[u] + 1) {
			int d = dfs(edge[i].v, std::min(edge[i].cap, max_flow - res));
			res += d, edge[i].cap -= d, edge[i ^ 1].cap += d;
			if (res == max_flow) break;
		}
	if (!res) dep[u] = -1;
	return res;
}
int Graph::Dinic() {
	int res = 0;
	while (bfs()) {
		memcpy(cur, head, sizeof head);
		res += dfs(0, inf);
	}
	//std::cout << res << std::endl;
	return res;
}
//Rhein_E
posted @ 2019-03-06 17:14  Rhein_E  阅读(121)  评论(0编辑  收藏  举报