• 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
    
  • 相关阅读:
    开启Spring Boot 之旅
    Java笔试面试练习题---集合
    Python
    Python
    Redis -下载与基本使用
    Git
    Vue全家桶-Vue-router&Vuex
    Es6
    Vue-前端
    Django基础及实战
  • 原文地址:https://www.cnblogs.com/Rhein-E/p/10484522.html
Copyright © 2020-2023  润新知