題意:
一個樹狀網絡,指定一個服務器s,一個距離k,與服務器相距爲k的節點都能被服務到,問服務整個網絡最少要增加多少臺服務器
分析:
這個網絡是無向的,轉成有向的比較好處理,題目給定了一個服務器,可以以這個點爲Root,把這個樹狀網絡變爲有向,然而比較優先的策略是從深度最深的葉子節點開始算距離爲k的位置放置一個服務器,然後更新覆蓋點,這裏只需要處理葉子節點,爲什麼? 因爲,如果葉子節點能被覆蓋的話,那麼非葉子節點要麼是服務器要麼已經被覆蓋了
Code:
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
#define MAXN 1000 + 10
int parent[MAXN], visit[MAXN];
vector<int> vertex[MAXN], depth[MAXN];
void conversion(int u, int p, int dep)
{
visit[u] = 1;
parent[u] = p;
//is leaf
if( 1 == vertex[u].size() && p == vertex[u][0] ) {
depth[dep].push_back(u);
}
for(int i = 0; i < vertex[u].size(); i ++) {
int v = vertex[u][i];
if( visit[v] ) {
continue;
}
conversion(v, u, dep+1);
}
}
inline void dfs(int u, int p, int k)
{
visit[u] = 1;
if( !k ) {
return;
}
for(int i = 0; i < vertex[u].size(); i ++) {
int v = vertex[u][i];
if( p == v ) {
continue;
}
dfs(v, u, k-1);
}
}
int cal(int n, int k, int s)
{
int sum = 0;
memset(visit, 0, sizeof(int)*(n+1));
for(int d = n-1; d > k; d --) { //already have a server.
for(int i = 0; i < depth[d].size(); i ++) {
int u = depth[d][i];
if( visit[u] ) {
continue;
}
int pu = u;
for(int j = 1; j <= k; j ++) {
pu = parent[pu];
}
dfs(pu, -1, k);
sum += 1;
}
}
return sum;
}
int main(int argc, char **argv)
{
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
#endif
int n, s, u, v, k, cas;
scanf("%d", &cas);
for( ; cas; cas --) {
scanf("%d %d %d", &n, &s, &k);
// init
for(int i = 1; i <= n; i ++) {
visit[i] = 0;
depth[i].erase(depth[i].begin(), depth[i].end());
vertex[i].erase(vertex[i].begin(), vertex[i].end());
}
for(int i = 1; i < n; i ++) {
scanf("%d %d", &u, &v);
vertex[u].push_back(v);
vertex[v].push_back(u);
}
//conversion undirect tree to direct tree
conversion(s, -1, 0);
printf("%d\n", cal(n, k, s));
}
return 0;
}