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;
}
标签:POI2007POW,get,int,rep,yy,Flood,fa,id
From: https://www.cnblogs.com/xiaruize/p/18136786