POI2007POW-The Flood

POI #Year2007 #并查集 #贪心

按高度从小到大按顺序考虑每个点,将同样高度的点按顺序全部合并完,然后再遍历这些同样大小的点,如果一个点为关键点且它的联通块中没有抽水机,那么这个位置联通块的最低位置放一个抽水机

可以证明这个贪心是最优的

// Author: xiaruize
const int N = 1e3 + 10;

int n, m;
struct node
{
	int x, y;
	int d;
} s[N * N];
int a[N][N];
int fa[N * N];
bool vis[N * N];
const int dx[4] = {1, -1, 0, 0};
const int dy[4] = {0, 0, 1, -1};

int id(int x, int y)
{
	return (x - 1) * m + y;
}

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

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

void solve()
{
	cin >> n >> m;
	rep(i, 1, n)
	{
		rep(j, 1, m)
		{
			cin >> a[i][j];
			s[id(i, j)] = {i, j, abs(a[i][j])};
			fa[id(i, j)] = id(i, j);
		}
	}
	sort(s + 1, s + n * m + 1, cmp);
	int res = 0;
	rep(i, 1, n * m)
	{
		int r = i;
		while (s[r].d == s[i].d)
			r++;
		r--;
		rep(j, i, r)
		{
			auto [x, y, d] = s[j];
			rep(dir, 0, 3)
			{
				int xx = x + dx[dir], yy = y + dy[dir];
				if (xx < 1 || yy < 1 || xx > n || yy > m)
					continue;
				if (abs(a[xx][yy]) > abs(a[x][y]))
					continue;
				vis[get(id(xx, yy))] |= vis[get(id(x, y))];
				fa[get(id(x, y))] = get(id(xx, yy));
			}
		}
		rep(j, i, r)
		{
			auto [x, y, d] = s[j];
			if (a[x][y] > 0 && !vis[get(id(x, y))])
			{
				vis[get(id(x, y))] = true;
				res++;
			}
		}
		i = r;
	}
	cout << res << endl;
}

#ifndef ONLINE_JUDGE
bool end_of_memory_use;
#endif

signed main()
{
	// freopen(".in","r",stdin);
	// freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int testcase = 1;
	// cin >> testcase;
	while (testcase--)
		solve();
#ifndef ONLINE_JUDGE
	cerr << "Memory use:" << (&end_of_memory_use - &start_of_memory_use) / 1024.0 / 1024.0 << "MiB" << endl;
	cerr << "Time use:" << (double)clock() / CLOCKS_PER_SEC * 1000.0 << "ms" << endl;
#endif
	return 0;
}
posted @ 2024-04-15 19:41  xiaruize  阅读(9)  评论(0)    收藏  举报