1. 程式人生 > >CodeForces - 1042F Leaf Sets

CodeForces - 1042F Leaf Sets

題面

題意

給出一棵樹,要求將其葉子分成幾個集合,要求每個集合中葉子兩兩之間的距離不大於k,求至少要將其分成幾個集合。

做法

因為n很大,所以考慮貪心。
首先dfs,我們可以自下而上逐個子樹考慮,對於一個子樹,可以將其拆成幾條鏈,可以將較短的幾條鏈合併在一起,而長的鏈獨自一個集合,然後其父節點與短鏈集合相連,這樣可以保證答案較優。
具體見程式碼,比較難描述。

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include
<algorithm>
#define N 1001000 using namespace std; int n,m,first[N],bb,ds[N],ans; struct Bn { int to,next; }bn[N<<1]; inline void add(int u,int v) { bb++; bn[bb].to=v; bn[bb].next=first[u]; first[u]=bb; } int dfs(int now,int last) { if(ds[now]==1) return 0; int i,j,p,q,t; vector<
int>use; use.clear(); for(p=first[now];p!=-1;p=bn[p].next) { if(bn[p].to==last) continue; use.push_back(dfs(bn[p].to,now)+1); } sort(use.begin(),use.end()); for(i=use.size()-1;i>=0;i--) { t=use[i]; if(i) t+=use[i-1]; if(t<=m) return use[i]; ans++; } return -N; } int main
() { memset(first,-1,sizeof(first)); int i,j,p,q; cin>>n>>m; for(i=1;i<n;i++) { scanf("%d%d",&p,&q); add(p,q),add(q,p); ds[p]++,ds[q]++; } for(i=1;i<=n;i++) if(ds[i]>1) break; if(dfs(i,-1)>0) ans++; cout<<ans; }