105.(并查集结合绝对值最小的01背包)选学霸
2016-03-21 06:30
253 查看
3372 选学霸[/b]
时间限制: 1s
空间限制:
128000 KB
题目等级 :
大师 Master
题解
题目描述 Description
老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一部分没有,同学们就会抗议。所以老师想请你帮他求出他该选多少学霸,才能既不让同学们抗议,又与原来的M尽可能接近。
输入描述 Input
Description
第一行,三个正整数N,M,K。
第2...K行,每行2个数,表示一对实力相当的人的编号(编号为1…N)。
输出描述 Output
Description
一行,表示既不让同学们抗议,又与原来的M尽可能接近的选出学霸的数目。(如果有两种方案与M的差的绝对值相等,选较小的一种。)
样例输入 Sample
Input
4 3 2
1 2
3 4
样例输出 Sample
Output
2
数据范围及提示 Data Size &
Hint
100%的数据N,P<=30000
分类标签 Tags 点此展开
动态规划 背包型DP 并查集 树结构基本思路:
输入时,采用并查集,把实力相同的人合并到一个集合,在一个循环,统计每个集合的人数,就像是物品
的体积,背包最多的体积不超过m,取与m之差的绝对值最小的那种方案(跑绝对值之差最小的01背包就行)。
代码:
#include<
cstdio >
#include<
iostream >
using namespace
std;
int
father[30001],f[30001*2];
int
wp1[30001]={0},wp[30001]={0};
int n,m,k;
int find(int
x)
{
if(father[x]!=x)
father[x]=find(father[x]);
return
father[x];
}
void unionn(int
a,int b)
{
father[b]=a;
}
void
input()
{
scanf("%d%d%d",&n,&m,&k);
for(int
i=1;i<=n;++i)
father[i]=i;
int a,b;
for(int
i=1;i<=k;++i)
{
scanf("%d%d",&a,&b);
int
r1=find(a);
int
r2=find(b);
if(r1!=r2)
unionn(r1,r2);
}
}
int main()
{
input();
for(int
i=1;i<=n;++i)
{
int
r1=find(i);
wp1[r1]++;
}
int t=0;
for(int
i=1;i<=n;++i)
{
if(wp1[i])
{
++t;
wp[t]=wp1[i];
}
}
for(int
i=1;i<=t;++i)
for(int j=2*m;j>=0;j--)
{
if(j-wp[i]>=0)
{
f[j]=max(f[j],f[j-wp[i]]+wp[i]);
}
}
int
people1=m-f[m];
int p;
int
people2;
for(int
j=m+1;j<=2*m;++j)
if(f[j]==j)
{
p=j;
people2=f[j];
break;
}
people2-=m;
if(people1>people2)
printf("%d\n",f[p]);
else
printf("%d\n",f[m]);
return 0;
}
相关文章推荐
- 随记
- 顺序表查找的优化
- 迷茫!前路无尽头
- TStack,TQueue,TObjectList,TObjectStack等等
- 加密方式&数字签名
- 二分查找
- poj 2623 快排
- 274. H-Index
- __int64与long long
- CentOS7安装vim7.4
- 新新新新新新到不行的新手手向:Spring在Eclipse中的配置方法
- Android Studio 常见问题
- [LeetCode] Range Sum Query 2D - Mutable 二维区域和检索 - 可变
- 学习Coding-iOS开源项目日志(一)
- 手机/电脑的定位方式
- Angular报错
- Python高级:细说Python浅拷贝和深拷贝
- Python高级:细说Python浅拷贝和深拷贝
- Mac NTFS 解决方法
- JAVA+MYSQL+JDBC