题目描述
Farmer John 最近买了些新电脑,它向为奶牛们提供上网的机会,但是上网需
要路由器,FJ 想尽量少买路由器。FJ 有 N 个(编号为 1..N)个农场,由 N-1 条
长度是 1 的边连接起来,没有环. FJ 可以决定把路由器放在哪些农场. 每个农场
只有长度为 K 的网线,该农场可以连接到距离小于等于 K 的路由器. 路由器本
身已经可以连接到互连网,可以被放置到任意的农场.
FJ 至少要买多少个路由器,才能让每个农场都能上网?农场想要上网的话,至
少要连接到一个包含路由器的农场.
多组询问
输入格式
第 1 行:一个整数 T,表示数据组数
第 2 行:两个整数: N 和 K
第 3..N 行: 每行两个整数 ai,bi,表示农场 ai 与 bi 之间有长度为 1 的边.
输出格式
共 T 行:每行一个整数,表示 FJ 至少需要买多少个路由器.
输入样例
1
8 2
3 6
7 1
1 8
2 4
1 4
4 5
2 6
输出样例
2
样例解释
在 1 号点和 2 号点安装路由器
数据范围
30%:n<=100
另外 10%:保证数据为一条链
100%:n<=100000,k<=10,T<=10
保证数据纯随机
因为一开始没有想到用一棵树来做,所以一直都没有想到正解,但是当我们把他想象成一棵树时,便可以用贪心解决。
我们先从最深的节点开始考虑,只要我们在它往上走k步到达的点上安装一个路由器便一定是最优的方案(正确性显然),于是我们可以用深搜来O(n)解决。
关键的是建立两个数组,分别记录从这个点往下走最远的不能上网的点(dis),和从这个点往下走最近的路由器的距离(near)。
然后我们再来处理什么情况下需要安装路由器什么情况下不需要安装。
如果dis等于k那么我们就必须在这里安装一个路由器(贪心)。
如果dis+near<=k那就代表这个点不需要安装路由器。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define ll long long #define il inline #define db double #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) using namespace std; il int gi() { int x=0,y=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') y=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*y; } struct edge { int next,to; }e[500045]; int head[500045],cnt,dis[500045],near[500045],k,n,ans; il void add(int from,int to) { e[++cnt].next=head[from]; e[cnt].to=to; head[from]=cnt; } il void dfs(int x,int fa) { dis[x]=0,near[x]=1e9; int r=head[x],now; while(r!=-1) { now=e[r].to; if(now!=fa) { dfs(now,x); dis[x]=max(dis[x],dis[now]+1); near[x]=min(near[x],near[now]+1); } r=e[r].next; } if(dis[x]+near[x]<=k) dis[x]=-1; if(dis[x]==k) dis[x]=-1,near[x]=0,ans++; } il void work() { memset(head,-1,sizeof(head)); ans=0,cnt=0; n=gi(),k=gi(); int x,y; for(int i=1;i<n;i++) { x=gi(),y=gi(); add(x,y); add(y,x); } dfs(1,0); if(dis[1]!=-1) ans++; printf("%d ",ans); } int main() { freopen("router.in","r",stdin); freopen("router.out","w",stdout); int T=gi(); for(int i=1;i<=T;i++) work(); return 0; }