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(2⋅l,sum[dep])
个节点被覆盖。等等,这个层是按什么分的层?没错,是按拓扑关系来分层。于是算法就能很愉快地出来了,累加出每一层对答案的贡献
min(2⋅l,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;
}