codevs3370 选学霸(背包dp,并查集)
2017-01-24 16:57
330 查看
3372 选学霸
时间限制: 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
/*利用并查集把有关连的人和在一起当一个物品,再01背包 此处背包无需考虑价值,只需用bool,true能取,false不能取 注意都不取的情况 */ #include <iostream> #include <cstring> #include <cmath> using namespace std; const int maxn=20005; int n,m,k,tot; int p[maxn]; int man[maxn]; int f[maxn+maxn]; int find(int x) { return (x==p[x]?x:p[x]=find(p[x])); } void solve() { memset(f,0,sizeof(f)); for(int i=1; i<=tot; i++) for(int j=2*m; j>=man[i]; j--)//2*m因为要求与m的绝对值 f[j]=max(f[j],f[j-man[i]]+man[i]);//01背包 for(int i=0; i<=m; i++) { if(f[m-i]==m-i) { cout<<m-i<<endl; return; } if(f[m+i]==m+i) { cout<<m+i<<endl; return; } } return; } int main() { cin>>n>>m>>k; int u,v; for(int i=1; i<=n; i++) p[i]=i; for(int i=1; i<=k; i++) { cin>>u>>v; int x=find(u); int y=find(v); p[x]=y; } memset(man,0,sizeof(man)); for(int i=1; i<=n; i++) man[find(i)]++; tot=0; for(int i=1; i<=n; i++) if(man[i]!=0) man[++tot]=man[i]; solve(); return 0; }
心若向阳,无言悲伤
相关文章推荐
- 【codevs3372】选学霸,并查集+可达性DP
- codevs2503失恋28天......(背包dp)
- 【日常学习】【背包DP】codevs1115 开心的金明题解
- Codevs_P1068 乌龟棋(DP+背包问题)
- BZOJ3163&Codevs1886: [Heoi2013]Eden的新背包问题[分治优化dp]
- <背包DP>codevs 1684 垃圾陷阱
- codevs 3372 选学霸(hash+并查集+多重背包)
- CODE[VS]3269 混合背包 (背包DP模板集合)
- Codevs3269 混合背包 经典背包dp
- codevs 2033 邮票 (背包)&& codevs 1047 邮票面值设计 (dfs+dp)
- 【日常学习】【背包DP】codevs1014 装箱问题题解
- 【日常学习】【背包DP】codevs1155 金明的预算方案题解
- 【基础练习】【背包DP】codevs1068 乌龟棋题解
- 树形DP+(分组背包||二叉树,一般树,森林之间的转换)codevs 1378 选课
- codevs1669 运输装备(背包dp)
- codevs 1297 硬币 (dp背包类型)
- Codevs_P1261 龙王的礼物(DP+背包)
- Codevs1115 开心的金明 ——2006年NOIP全国联赛普及组 普通背包dp
- 选学霸(codevs 3372)
- 【区间dp】codevs1966 乘法游戏