題目大意:n臺機器連成一個樹狀網絡,其中葉節點是客戶端,其他節點是服務器。現在有一臺服務器在節點s,服務器能傳播的信號的距離爲k,因爲有的用戶距離服務器的距離大於k,所以必須添加服務器。問最少要添加幾個服務器,才能使每個客戶端都收到信號
分析:首先以S爲根節點建立一顆有根樹,並dfs建樹時記錄點的深度,是否爲葉子。
把葉子按深度從大到小排序,每次貪心選一個深度最大的葉子,然後找到他的k級祖先,以k級祖先出發dfs標記K層以內的葉子,如此反覆直到葉子都被染色。
複雜度O (N)
本代碼存在部分bug:實在未能發現,望指導
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1005;
vector <int> node[maxn], mapp[maxn];
int fa[maxn], n, s, k;
bool vis[maxn];
void dfs(int u, int f, int d){ //尋找葉子結點
fa[u] = f;
if (mapp[u].size() == 1 && d>k) node[d].push_back(u); //避開按深度排序
for (int i = 0; i<mapp[u].size(); i++){
int v = mapp[u][i];
if (v != f) dfs(v, u, d+1);
}
}
void dfs2(int u, int f, int d){
vis[u] = true;
for (int i = 0; i<mapp[u].size(); i++){
int v = mapp[u][i];
if (v != f && d<k) dfs(v, u, d+1);
}
}
int solve(){
int ans = 0;
memset(vis, 0, sizeof(vis));
for (int d = n-1; d>k; d++)
for (int i = 0; i<node[d].size(); i++){ //從深度最大出發,貪心
int u = node[d][i];
if (vis[u]) continue;
int v = u;
for (int i = 0; i<k; i++) v = fa[v]; //尋找k級祖先
dfs2(v, -1, 0);
ans++;
}
return ans;
}
int main(){
int T;
scanf("%d", &T);
while (T--){
scanf("%d%d%d", &n, &s, &k);
for (int i = 1; i<=n; i++){
mapp[i].clear();
node[i].clear();
}
for (int i = 0; i<n; i++){
int a, b;
scanf("%d%d", &a, &b);
mapp[a].push_back(b);
mapp[b].push_back(a);
}
dfs(s, -1, 0);
printf("%d\n", solve());
}
return 0;
}