您的位置:首页 > 其它

【codevs3372】选学霸,并查集+可达性DP

2015-12-13 14:16 309 查看
选学霸

时间限制: 1 s

空间限制: 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

写在前面:感谢Shallwe的帮助

——————————————————————————————————————————————

思路:用并查集初始化,然后当作可达性背包来做(由于数据比较弱,没有O(15000*30000)的卡人数据)就可以了

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
int father[30010],num[30010],a[30010];//a数组存放物品标号,num存放每个物品的价值(对于选i来说必须要选的人数)
bool f[60010];
int n,m,k,ans;
int find(int x)
{
if (x!=father[x]) father[x]=find(father[x]);
return father[x];
}
void pd(int x,int y)
{
if (abs(m-x)<abs(m-y)) ans=x;
}
main()
{
int x,y,p,q;
int t;
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=n;i++) father[i]=i;
for (int i=1;i<=k;i++)
{
scanf("%d%d",&x,&y);
p=find(x);q=find(y);
if (p!=q) father[p]=q;
}
for (int i=1;i<=n;i++)
{
t=find(i);
num[t]++;
if (num[t]==1) a[++a[0]]=t;
}
f[0]=1;
for (int i=1;i<=a[0];i++)
for (int j=2*m;j>=num[a[i]];j--)
f[j]=max(f[j-num[a[i]]],f[j]);
for (int i=m;i>=0;i--) if (f[i]) {ans=i;break;}
for (int i=m;i<=2*m;i++)
if (f[i]) pd(i,ans),printf("%d",ans),exit(0);
printf("%d",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: