P2170 选学霸

传送门

思路:

  ① 可以把每个学生都看作点,而那些实力相同的学生就处在同一个连通块内,因为连通块内的同学要么都取,要么不取,所以可以将连通块缩成一个点。只需用并查集维护每个连通块的大小。

  ② 接着采取神奇的可行性DP:用 f[ i ] 判断选出 i 个学生的方案是否可行。可行就转移 。

  伪代码:

    初始化: f[ 0 ] =true;

    for( j: 1~n ) //枚举点

      for( i: n-size ~0 ) //逆序,,

        if( f[ i ] )

          f [ i - size ] =true.( size 为枚举到的点大小)

  ③ 最后只要暴力地从 m 左右两边找出离 m 最近的  f[ i ] == true,就是答案。

Code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<stack>
#include<vector>
#include<queue>
#include<deque>
#include<map>
#include<set>
using namespace std;
#define lck_max(a,b) ((a)>(b)?(a):(b))
#define lck_min(a,b) ((a)<(b)?(a):(b))
typedef long long LL;
const int maxn=4e5+7;
inline LL lck_abs(LL a) {return a>0?a:-a;}
inline LL read()
{
    LL kr=1,xs=0;
    char ls;
    ls=getchar();
    while(!isdigit(ls))
    {
        if(!(ls^45))
            kr=-1;
        ls=getchar();
    }
    while(isdigit(ls))
    {
        xs=(xs<<1)+(xs<<3)+(ls^48);
        ls=getchar();
    }
    return xs*kr;
}
inline void out(LL xs)
{
    if(!xs) {putchar(48); return;}
    if(xs<0) putchar('-'),xs=-xs;
    int kr[57],ls=0;
    while(xs) kr[++ls]=xs%10,xs/=10;
    while(ls) putchar(kr[ls]+48),ls--;
}
LL fa[maxn],si[maxn];//si 维护连通块大小
inline LL find(LL u) 
{
    return fa[u]==u?fa[u]:find(fa[u]);
}
LL n,m,k,u,v,i,j,l,r,ans,top,st[maxn];bool f[maxn];
int main()
{
    n=read();m=read();k=read();
    for(i=1;i<=n;i++)
        fa[i]=i,si[i]=1;
    for(i=1;i<=k;i++)
    {
        u=read();v=read();
        LL r1=find(u),r2=find(v);
        if(r1==r2) continue;
        fa[r2]=r1,si[r1]+=si[r2];
    }
    for(LL i=1;i<=n;i++)
        if(fa[i]==i) st[++top]=i;//缩点
    f[0]=true;
    for(i=1;i<=top;i++)//枚举点
        for(j=n-si[st[i]];j>=0;j--)//可达性DP 
            if(f[j])
                f[j+si[st[i]]]=true;
    for(i=m;!f[i];i--); l=m-i;//找到比m小的最接近的人数
    for(i=m;!f[i];i++); r=i-m;//找到比m大的最接近的人数
    if(r>=l) out(m-l),putchar('
');
    else out(m+r),putchar('
');
return 0;
}
原文地址:https://www.cnblogs.com/lck-lck/p/9846429.html