[POI2007]洪水pow 并查集

版权声明:xgc原创文章,未经允许不得转载。 https://blog.csdn.net/xgc_woker/article/details/82905412

Description
给你n*m的图,每个点有一个海拔,在较低的点放置吸水器能吸到比较高的点,有一些点是必须要吸的,问你最少需要多少吸水器。


Sample Input
6 9
-2 -2 -1 -1 -2 -2 -2 -12 -3
-2 1 -1 2 -8 -12 2 -12 -12
-5 3 1 1 -12 4 -6 2 -2
-5 -2 -2 2 -12 -3 4 -3 -1
-5 -6 -2 2 -12 5 6 2 -1
-4 -8 -8 -10 -12 -8 -6 -6 -4


Sample Output
2


将权值从小到大排序,对于每一个点去四周寻找已经染过的点。
然后每染完一个权值就判断一下,他所处的集合中是否有吸水器。


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int dx[4] = {0, 1, 0, -1};
const int dy[4] = {1, 0, -1, 0};
int read() {
	int s = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * f;
}

struct node {
	int x, y, c;
} a[1100000];
bool v[1100000], ned[1100000];
int n, m, w[1100000], fa[1100000];

bool cmp(node a, node b) {return a.c < b.c;}

int findfa(int x) {
	if(fa[x] != x) fa[x] = findfa(fa[x]);
	return fa[x];
}

void findw(int x, int y) {
	int u = (x - 1) * m + y;
	for(int k = 0; k < 4; k++) {
		int nx = x + dx[k], ny = y + dy[k];
		if(nx <= 0 || ny <= 0 || nx > n || ny > m) continue;
		int y = (nx - 1) * m + ny;
		if(v[y]) {
			int fy = findfa(y), fu = findfa(u);
			fa[fu] = fy; w[fy] |= w[fu];
		}
	}
}

int main() {
	n = read(), m = read();
	for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) {
		int x = (i - 1) * m + j;
		a[x].x = i, a[x].y = j, a[x].c = read();
		if(a[x].c < 0) a[x].c = abs(a[x].c), ned[x] = 1;
	} sort(a + 1, a + n * m + 1, cmp);
	int last = 1, ans = 0;
	for(int i = 1; i <= n * m; i++) fa[i] = i;
	for(int i = 1; i <= n * m; i++) {
		findw(a[i].x, a[i].y);
		if(a[i].c != a[i + 1].c) {
			for(int j = last; j <= i; j++) {
				int x = (a[j].x - 1) * m + a[j].y;
				if(!ned[x]) {
					int fx = findfa(x);
					if(!w[fx]) 
					ans++, w[fx] = 1;
				}
			} last = i + 1;
		} v[(a[i].x - 1) * m + a[i].y] = 1;
	} printf("%d\n", ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xgc_woker/article/details/82905412