T1 P2170 选学霸
传送门:洛谷P2170
本题考察的是并查集优化背包DP,所以我们通过并查集将 \(n\) 个点变成 \(group\) 个连通块,那么每个连通块里面的点要么都选要么都不选,状态 \(dp[i]\) 定义为可以选 \(i\) 个学霸且不会抗议,算出所有可能的结果,再枚举 \(1\) ~ \(n\) ,求出最接近 \(m\) 的可能的值;
贴代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e4 + 5;
int n, m, k, group, dp[maxn], fa[maxn], siz[maxn], f[maxn];
int Find(int x) {
if (x == fa[x]) return fa[x];
return fa[x] = Find(fa[x]);//很重要的路径压缩
}
void read() {
scanf("%d%d%d", &n, &m, &k);
group = n;
for (int i = 1; i <= n; ++ i)
fa[i] = i, siz[i] = 1;
for (int i = 1, u, v; i <= k; ++ i) {
scanf("%d%d", &u, &v);
int fu = Find(u), fv = Find(v);
if (fu != fv) {
group --;
fa[fu] = fv;
siz[fv] += siz[fu];
}
}
dp[0] = dp[n] = 1;
for (int i = 1; i <= n; ++ i) {
int fi = Find(i);
if (f[fi]) continue ;
f[fi] = 1;
for (int j = n - siz[fi]; j >= 0; -- j) {
if (dp[j]) dp[j + siz[fi]] = 1;
}
}
int minl = 1e9 + 7, minr = 1e9 + 7;
for (int i = 0; i <= m; ++ i)
if (dp[i]) minl = min(minl, m - i);
for (int i = m; i <= n; ++ i)
if (dp[i]) minr = min(minr, i - m);
if (minl == minr) printf("%d\n", m - minl);
else if (minr < minl) printf("%d\n", m + minr);
else printf("%d\n", m - minl);
}
int main() {
read();
return 0;
}
标签:group,14,int,2023.04,T1,fa,maxn,dp
From: https://www.cnblogs.com/florence25/p/17319312.html