码迷,mamicode.com
首页 > 其他好文 > 详细

3372 选学霸

时间:2016-08-17 07:53:48      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:

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

分类标签 Tags 点此展开 

 
 
AC代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n,m,k;
const int maxn=30000;
int fa[maxn],v[maxn],c[maxn];
int find(int x){
    if(fa[x]==x) return x;
    else fa[x]=find(fa[x]);
    return fa[x];
}
void sh(int x,int y){
    int rx=find(x);
    int ry=find(y);
    if(rx!=ry)
        fa[ry]=rx;//如果两个点不在一棵树内,那么吧x这个树的跟节点给挂到y这个树的根节点上面 
}
void first(int n){
    for(int i=1;i<=n;i++) 
        fa[i]=i;  

}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    first(n);
    for(int i=1,a,b;i<=k;i++){
        scanf("%d%d",&a,&b);
        sh(a,b);
    }
    for(int i=1;i<=n;i++) fa[i]=find(i);      
    sort(fa+1,fa+n+1);//排序 
    int cnt=1,x=find(1);
    v[cnt]=1;
    for(int i=2;i<=n;i++)//统计并查集个数 
        if(fa[i]==x) v[cnt]++;
        else{
            v[++cnt]++;
            x=fa[i];
        }
    for(int i=1;i<=cnt;i++)//减少时间 
        for(int j=m*2;j>=v[i];j--)
            c[j]=max(c[j],c[j-v[i]]+v[i]);
    int m1,m2;
    //for(int i=m;i>=0;i--)
    //if(c[i]==i) {m1=abs(m-i);break;}
    m1=m-c[m]; //少循环一遍 
    for(int i=m+1;i<=2*m;i++)
        if(c[i]==i) {m2=abs(m-i);break;}
    if(m1<=m2)   printf("%d\n",m-m1);//输出绝对值较小者      
    else printf("%d\n",m+m2); 
    return 0;
}

 

3372 选学霸

标签:

原文地址:http://www.cnblogs.com/shenben/p/5778515.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!