语言:C++14(GCC9) O2
这里把题目中的 k 换成了 c。
//程序算法:并查集,01背包,DP
#include <bits/stdc++.h>
using namespace std;
const int N=20010;
int p[N],rk[N],cnt[N],d[N];//c[]:并查集元素个数 d[]:DP数组
int n,m,c;
inline void make_set(int x)
{
p[x]=x;
rk[x]=cnt[x]=1;
}
int find(int x)
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
int union_set(int x,int y)
{
if(x!=y)
{
x=find(x),y=find(y);
if(rk[x]<rk[y])swap(x,y);
p[y]=x,cnt[x]+=cnt[y];
if(rk[x]==rk[y])rk[x]++;
}
return x;
}
int main()
{
scanf("%d %d %d",&n,&m,&c);
if(c==0&&n>=m)
{
printf("%d\n",m);
return 0;
}
for(int i=1;i<=n;i++)make_set(i);
for(int i=1;i<=c;i++)
{
int x,y;
scanf("%d %d",&x,&y);
union_set(x,y);
}//并查集基本操作
for(int i=1;i<=n;i++)//01背包模板
{
if(find(i)!=i)continue;
for(int j=n;j>=cnt[i];j--)
d[j]=max(d[j],d[j-cnt[i]]+cnt[i]);
}
int ans,minm=0x3f3f3f3f;
for(int i=0;i<=n;i++)//判断最接近m的人数
if(abs(d[i]-m)<minm)minm=abs(d[i]-m),ans=d[i];
printf("%d\n",ans);
return 0;
}