• [CQOI2017]老C的方块


    题意:

    老C是个程序员。
    游戏被限定在一个由小方格排成的R行C列网格上,有些相邻的小方格之间的公共边比较特殊。
    特殊的公共边排列得有很强的规律,下图所示是一个R=C=8的网格,蓝色标注的边是特殊边。
    如果网格的规模更大,我们可以用同样的方法找出所有的特殊边。
    网格的每个小方格刚好可以放入一个小方块,在游戏的一开始,有些小方格已经放上了小方块,另外的小方格没有放。
    有一些小方块排列成了它讨厌的形状(特殊边的位置也要如图中所示),即使是经过任意次旋转、翻转。
    为了防止弃疗,老C决定移除一些格子里小方块,使得剩下的小方块不能构成它讨厌的形状。
    但是游戏里每移除一个方块都是要花费一些金币的,老C当然希望尽可能少的使用游戏里的金币。
    

    题解:

    网络流。
    首先,观察题目中的图

    可以发现,蓝边周围的两个点,要么破坏一个,要么破坏周围的。而周围的都满足距离为奇数。
    看到这个条件,又是网格图,可以黑白染色。
    这样,周围的点的颜色一定不同,可以建二分图,使用最小割。
    然而,有一个“要么破坏一个,要么破坏周围的。”的要求,即“或”的限制。
    在最小割中,“或”就是串联,这个割掉一个就破坏了路径。
    而周围的破坏所有才行,即“与”,就是并联。
    把中间两个点连min的边,周围的点并联,再串联到中间的点上。
    如图

    最小割即可,跑不满,所以能过。
    注意建图细节。

    代码:

    #include <stdio.h> 
    #include <map> 
    using namespace std;
    #define N 200010
    #define M 1000010
    #define min(a, b) a < b ? a: b
    #define ll long long 
    int fr[N],ne[M],v[M],w[M],bs = 0;
    void add(int a, int b, int c) {
    	v[bs] = b;
    	w[bs] = c;
    	ne[bs] = fr[a];
    	fr[a] = bs++;
    }
    int dl[N],jl[N],dy[N],S,T,n,inf = 2000000000;
    bool bk[N];
    bool bfs() {
    	for (int i = 1; i <= n; i++) {
    		bk[i] = false;
    		jl[i] = inf;
    	}
    	int he = 0,	ta = 1;
    	dl[he] = S;
    	bk[S] = true;
    	jl[S] = 0;
    	while (he < ta) {
    		int u = dl[he];
    		for (int i = fr[u]; i != -1; i = ne[i]) {
    			if (w[i] > 0 && !bk[v[i]]) {
    				bk[v[i]] = true;
    				jl[v[i]] = jl[u] + 1;
    				dl[ta++] = v[i];
    			}
    		}
    		he += 1;
    	}
    	return jl[T] < inf;
    }
    int dfs(int u, int z) {
    	if (u == T) return z;
    	for (int & i = dy[u]; i != -1; i = ne[i]) {
    		if (w[i] > 0 && jl[v[i]] == jl[u] + 1) {
    			int rt = dfs(v[i], min(w[i], z));
    			if (rt != -1) {
    				w[i] -= rt;
    				w[i ^ 1] += rt;
    				return rt;
    			}
    		}
    	}
    	return - 1;
    }
    int dinic() {
    	int jg = 0;
    	while (bfs()) {
    		for (int i = 1; i <= n; i++) dy[i] = fr[i];
    		while (1) {
    			int rt = dfs(S, inf);
    			if (rt == -1) break;
    			jg += rt;
    		}
    	}
    	return jg;
    }
    void addb(int a, int b, int c) {
    	add(a, b, c);
    	add(b, a, 0);
    }
    int x[100010],y[100010],z[100010],fx[6][2] = {-1,0,1,0,0,-1,-1,1,1,1,0,2},r,c;
    map < ll,int > mp;
    bool check(int x, int y) {
    	if (x % 2 == 1) return y % 4 == 1;
    	else return y % 4 == 3;
    }
    int getwz(int x, int y) {
    	if (x <= 0 || x > r || y <= 0 || y > c) return - 1;
    	ll t = 1ll * x * c + y;
    	if (mp.count(t) == 0) return - 1;
    	return mp[t];
    }
    void link(int z1, int z2, int a, int b) {
    	addb(a, b, min(z[z1], z[z2]));
    	for (int s = 0; s < 6; s++) {
    		int tx = x[z1] + fx[s][0],
    		ty = y[z1] + fx[s][1];
    		int wz = getwz(tx, ty);
    		if (wz == -1) continue;
    		if ((tx + ty) % 2 == 0) addb(wz + 3, a, inf);
    		else addb(b, wz + 3, inf);
    	}
    }
    int main() {
    	int m;
    	scanf("%d%d%d", &c, &r, &m);
    	for (int i = 0; i < m; i++) scanf("%d%d%d", &y[i], &x[i], &z[i]);
    	S = 1;	T = 2;	n = m + 2;
    	for (int i = 1; i <= n; i++) fr[i] = -1;
    	for (int i = 0; i < m; i++) {
    		if ((x[i] + y[i]) % 2 == 0) addb(S, i + 3, z[i]);
    		else addb(i + 3, T, z[i]);
    		mp[1ll * x[i] * c + y[i]] = i;
    	}
    	for (int i = 0; i < m; i++) {
    		int t;
    		if (check(x[i], y[i]) && (t = getwz(x[i], y[i] + 1)) != -1) {
    			fr[n + 1] = fr[n + 2] = -1;
    			link(i, t, n + 1, n + 2);
    			n += 2;
    		}
    	}
    	printf("%d", dinic());
    	return 0;
    }
    
  • 相关阅读:
    eclipse-SDK-3.7-win32;eclipse-java-indigo-win32;eclipse-jee-indigo-win32 区别(ZZ)
    Marketplace Client- Download
    Log4J2基本配置
    Map 迭代 两种方法
    Python Argparse模块
    Python操作Memcached
    MySQL参数调优
    Nginx调优
    JavaScript知识点总结[部分]
    python optparser模块
  • 原文地址:https://www.cnblogs.com/lnzwz/p/11366589.html
Copyright © 2020-2023  润新知