题目描述
老师想从 n 名学生中选 m 人当学霸,但有 k 对人实力相当,如果实力相当的人中,一部分被选上,另一部分没有,同学们就会抗议。所以老师想请你帮他求出他该选多少学霸,才能既不让同学们抗议,又与原来的 m 尽可能接近。
输入格式
第一行,三个正整数 n,m,k。
第 2 至第 k 行,每行 2 个数,表示一对实力相当的人的编号(编号为 1,2,...,n)。
输出格式
一行,表示既不让同学们抗议,又与原来的 m 尽可能接近的选出学霸的数目。
如果有两种方案与 m 的差的绝对值相等,选较小的一种。
输入输出样例
输入 #1
4 3 2 1 2 3 4
输出 #1
2
说明/提示
对于 100% 的数据,满足 1≤n,m≤2×10^4。
AC代码
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int N = 2e4 + 100;
int n, m, k;
int fa[N], dp[N], p[N];
int find(int x) {
if (fa[x] == x) {
return x;
}
return fa[x] = find(fa[x]);
}
void merge(int x, int y) {
int fx = find(x);
int fy = find(y);
if (fx != fy) {
fa[fy] = fx;
p[fx] += p[fy];
}
}
int main() {
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
fa[i] = i;
p[i] = 1;
}
for (int i = 1; i <= k; i++) {
int x, y;
cin >> x >> y;
merge(x, y);
}
int minn = 20010, ans;
dp[0] = 1;
for (int i = 1; i <= n; i++) {
if (fa[i] == i) {
for (int j = n; j >= p[i]; j--) {
if (dp[j - p[i]] == 1) {
dp[j] = 1;
}
}
}
}
for (int i = 0; i <= n; i++) {
if (dp[i] == 1) {
if (minn > abs(m - i)) {
minn = abs(m - i);
ans = i;
}
}
}
cout << ans << endl;
return 0;
}