BZOJ 1517 [POI2006]Met

题解 专栏收录该内容
16 篇文章 0 订阅

title: ‘BZOJ 1517 [POI2006]Met’
categories: BZOJ
date: 2015-10-21 16:54:00
tags: [贪心,拓扑排序]


Description

给出一棵N个结点的树,选择L条路径,覆盖这些路径上的结点,使得被覆盖到的结点数最多。

Input

第一行两个正整数N、L(2 <= N <= 1,000,000, 0 <= L <= N)。下面有N-1行,每行两个正整数A和B(1 <= A, B <= N),表示一条边(A,B)。

Output

一个整数,表示最多能覆盖到多少结点。

Sample

input.txt
17 3
1 2
3 2
2 4
5 2
5 6
5 8
7 8
9 8
5 10
10 13
13 14
10 12
12 11
15 17
15 16
15 10

output.txt
13

Solution

(试一试刚学到的爆炸读入优化,2333333)
一开始想乱贪,找什么树的直径,然而复杂度挺爆炸的,正确性也不能证明。
于是只能看了一发题解,发现人家说:选择路径的代价相同显然考虑贪心。
很有道理的样子。
我们发现每条路径一定是从一个叶子节点(度为1的节点)到另一个叶子节点,于是叶子节点这一层上面一定会选l对节点,即2*l个节点,而叶子节点上又一定能拓展往它的上一层,于是我们发现,每一层都能选出 min(2l,sum[dep]) 个节点被覆盖。等等,这个层是按什么分的层?没错,是按拓扑关系来分层。于是算法就能很愉快地出来了,累加出每一层对答案的贡献 min(2l,sum[dep]) 即可。
然而我发现以前自己拓扑都是用栈打的,所以分出的层不均匀,WA了几万年。什么叫分出的层不均匀?比如在1-2-3-4这条链上,它们的层数会被划分成:1,2,3,1;然而正确的层数应该是:1,2,2,1。于是我们把栈改用队列就可以了,看来以后还是要提高一下自己的姿势水平。

Code

#include<stack>
#include<queue>
#include<cstdio>
#include<cstdarg>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#ifdef __GNUC__
#include<unistd.h>
#endif

#define maxn 1000000+5

using namespace std;

//#define UsingIOException
static class Scanner
{
    typedef double D;
    typedef unsigned int long II;
    typedef signed int long SI;
    typedef unsigned char S;
    typedef char C;
    typedef bool B;
    static II const ScL =16384,Eof =0xff;
#ifdef __GNUC__
    II const buffer;
#else
    FILE *const buffer;
#endif
    S ram[ScL],*begin,*end;
public:
#ifdef UsingIOException
    enum IOException
    {
        FileEof,TypeError
    };
#endif
#ifdef __GNUC__
#ifdef Fin
    Scanner(II const iobuffer=open(Fin,1)):buffer(iobuffer),begin(ram),end(ram)
#else
    Scanner(II const iobuffer=0):buffer(iobuffer),begin(ram),end(ram)
#endif
#else
#ifdef Fin
    Scanner(FILE *const iobuffer=fopen(Fin,"rb")):buffer(iobuffer),begin(ram),end(ram)
#else
    Scanner(FILE *const iobuffer=stdin):buffer(iobuffer),begin(ram),end(ram)
#endif
#endif
    {
    }
    ~Scanner(void)
    {
#ifdef __GNUC__
        close(buffer);
#else
        fclose(buffer);
#endif
    }
    II get(void)
    {
        if(begin==end)
        {
            begin=ram;
#ifdef __GNUC__
            if((end=(begin=ram)+read(buffer,ram,ScL))==ram)
#else
            if((end=(begin=ram)+fread(ram,1,ScL,buffer))==ram)
#endif
                return Eof;
        }
        return *begin++;
    }
    D getSD(void)
    {
        II j;
        while(isspace(j=get()));
        B neg=false;
        if(j=='-')
        {
            neg=true;
            j=get();
        }
#ifdef UsingIOException
        if(!isdigit(j))
            throw j==Eof?FileEof:TypeError;
#endif
        SI i=j-'0';
        while(isdigit(j=get()))
            i=(i<<3)+(i<<1)+(j-'0');
        if(j=='.')
        {
            D val=D(i),level=1.;
            while(isdigit(j=get()))
                val+=(level*=.1)*D(j-'0');
            return neg?-val:val;
        }
        return neg?-i:i;
    }
    D getD(void)
    {
        II j;
        while(isspace(j=get()));
#ifdef UsingIOException
        if(!isdigit(j))
            throw j==Eof?FileEof:TypeError;
#endif
        II i=j-'0';
        while(isdigit(j=get()))
            i=(i<<3)+(i<<1)+(j-'0');
        if(j=='.')
        {
            D val=D(i),level=1.;
            while(isdigit(j=get()))
                val+=(level*=.1)*D(j-'0');
            return val;
        }
        return i;
    }
    SI getSI(void)
    {
        II j;
        while(isspace(j=get()));
        B neg=false;
        if(j=='-')
        {
            neg=true;
            j=get();
        }
#ifdef UsingIOException
        if(!isdigit(j))
            throw j==Eof?FileEof:TypeError;
#endif
        SI i=j-'0';
        while(isdigit(j=get()))
            i=(i<<3)+(i<<1)+(j-'0');
        return neg?-i:i;
    }
    II getII(void)
    {
        II j;
        while(isspace(j=get()));
#ifdef UsingIOException
        if(!isdigit(j))
            throw j==Eof?FileEof:TypeError;
#endif
        II i=j-'0';
        while(isdigit(j=get()))
            i=(i<<3)+(i<<1)+(j-'0');
        return i;
    }
    II getS(void)
    {
        II j;
        while(isspace(j=get()));
#ifdef UsingIOException
        if(!isascii(j))
            throw j==Eof?FileEof:TypeError;
#endif
        return j;
    }
    C * getCS(C *p)
    {
        skip();
        while(!isspace(*p++=get()));
        *--p='\0';
        return p;
    }
    void skip(int (*const func)(int)=isspace)
    {
        while(func(get()));
        --begin;
    }
}scan;
static class Printer
{
    typedef unsigned int long II;
    typedef char C;
    static II const ScL =16384,Ral =100;
    C self[ScL+Ral],*sp,*const slimit;
    FILE *const buffer;
public:
#ifdef Fout
    Printer(FILE *const iobuffer=fopen(Fout,"wb")):sp(self),slimit(self+ScL),buffer(iobuffer)
#else
    Printer(FILE *const iobuffer=stdout):sp(self),slimit(self+ScL),buffer(iobuffer)
#endif
    {
    }
    ~Printer(void)
    {
        flush();
        fclose(buffer);
    }
    void flush(void)
    {
        fwrite(self,1,sp-self,buffer);
        sp=self;
    }
    void print(C const *const s,...)
    {
        va_list h;
        va_start(h,s);
        if((sp+=vsprintf(sp,s,h))>=slimit)
            flush();
        va_end(h);
    }
    void puts(C const *const s)
    {
        if((sp+=strlen(strcpy(sp,s)))>=slimit)
            flush();
    }
    void putchar(II const x)
    {
        *sp++=(C)x;
        if(sp>=slimit)
            flush();
    }
}sysout;

vector <int> a[maxn];
queue <int> q;

int du[maxn],sum[maxn],dep[maxn];
int n,l,ans,cnt;

void Toposort(){
    for(int i=1;i<=n;i++)
        if(du[i]==1) q.push(i),dep[i]=1,sum[1]++;
    while(!s.empty()){
        int x=q.front(); q.pop();
        int len=a[x].size();
        cnt=max(cnt,dep[x]);
        for(int i=0;i<len;i++)
            if(du[a[x][i]]!=1){
                du[a[x][i]]--;
                if(du[a[x][i]]==1){
                    dep[a[x][i]]=dep[x]+1;
                    sum[dep[x]+1]++;
                    q.push(a[x][i]);
                }
            }
    }
    for(int i=1;i<=cnt;i++)
        ans+=min(2*l,sum[i]);
}

int main(){
    n=scan.getSI(); l=scan.getSI();
    for(int i=1;i<n;i++){
        int x,y;
        x=scan.getSI();
        y=scan.getSI();
        a[x].push_back(y);
        a[y].push_back(x);
        du[x]++; du[y]++;   
    }
    Toposort();
    printf("%d",ans);
    return 0;   
}
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值