• 方格取数问题


    题目链接:

    点我

    题目分析:

    网络流
    考虑先将棋盘黑白染色变成二分图,这样使得每个格子有公共边的其他格子和它自己都是异色的,然后把它向其他四个方向的点连一下边,边容量(INF)(S)连黑点,容量为权值,白点连(T),容量同理
    于是问题转化为一个最小割问题

    代码:

    #include<bits/stdc++.h>
    #define INF (1000000000 + 7)
    #define N (100000 + 10)
    using namespace std;
    inline int read() {
    	int cnt = 0, f= 1;char c = getchar();
    	while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
    	while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + (c ^ 48); c = getchar();}
    	return cnt * f;
    }
    const int fx[5] = {0, 1, 0, -1, 0};
    const int fy[5] = {0, 0, -1, 0, 1};
    int m, n, s, t, first[N << 2], nxt[N << 2], to[N << 2], flow[N], tot = 1, dep[N], cnt[N], ans;
    void add(int x, int y, int z) {nxt[++tot] = first[x], first[x] = tot, to[tot] = y, flow[tot] = z;}
    int Map[110][110];
    queue <int> q;
    void build () {
    	for (register int i = 1; i <= m; ++i) 
    		for (register int j = 1; j <= n; ++j) {
    			if ((i + j) & 1) add(s, (i - 1) * n + j, Map[i][j]), add((i - 1) * n + j, s, 0);
    			else add(t, (i - 1) * n + j, 0), add((i - 1) * n + j, t, Map[i][j]);
    		}
    	for (register int i = 1; i <= m; ++ i)
    		for (register int j = 1; j <= n; ++j) {
    			if ((i + j) & 1) {
    				for (register int k = 1; k <= 4; ++k) {
    					int x = i + fx[k], y = j + fy[k];
    					if (x < 1 || y < 1 || x > m || y > n) continue;
    					add((i - 1) * n + j, (x - 1) * n + y, INF);
    					add((x - 1) * n + y, (i - 1) * n + j, 0);
    				}
    			}
    		}
    }
    void bfs_(int t) {
    	memset(dep, 0xff, sizeof dep);
    	dep[t] = 0, cnt[0] = 1;
    	q.push(t);
    	while (!q.empty()) {
    		int p = q.front(); q.pop();
    		for (register int i = first[p]; i; i = nxt[i]) {
    			int v = to[i];
    			if (dep[v] == -1) {
    				++cnt[dep[v] = dep[p] + 1];
    				q.push(v);
    			}
    		}
    	}
    }
    int max_flow;
    int dfs_(int p, int f) {
    	if (p == t) {max_flow += f; return f;}
    	int u = 0;
    	for (register int i = first[p]; i; i = nxt[i]) {
    		int v = to[i];
    		if (flow[i] && dep[v] == dep[p] - 1) {
    			int uu = dfs_(v, min(flow[i], f - u));
    			if (uu) {
    				flow[i] -= uu, flow[i ^ 1] += uu, u += uu;
    			}
    			if (u >= f) return u;
    		}
    	}
    	if (!--cnt[dep[p]]) dep[s] = m * n + 3;
    	++cnt[++dep[p]];
    	return u;
    }
    int main() {
    	m = read(), n = read();
    	s = m * n + 1, t = m * n + 2;
    	for (register int i = 1; i <= m; ++i) 
    		for (register int j = 1; j <= n; ++j) 
    			Map[i][j] = read(), ans += Map[i][j];
    	build();
    	bfs_(t);
    	while (dep[s] < m * n + 3) dfs_(s, INF);
    	printf("%d", ans - max_flow);
    	return 0;
    }
    
  • 相关阅读:
    Centos 5.5+PHP5 添加phpjavabrige
    Google /Baidu Ping服务快速收录php
    基站一些信息
    搜索引擎提交入口收集
    druid简单教程
    http关于application/xwwwformurlencoded等字符编码的解释说明
    对比.NET PetShop和Duwamish来探讨Ado.NET的数据库编程模式。
    WinForm RTF生成器
    在 Visual C# .NET 中跟踪和调试
    c#中构建异常处理
  • 原文地址:https://www.cnblogs.com/kma093/p/11839577.html
Copyright © 2020-2023  润新知