人生第一道图论题啊,有木有
题意:
有一个树状网络,有一个原始服务器s,它的服务范围是k
问至少再放多少台服务范围是k的服务器才能使网络中的每个节点都被覆盖掉
解法:
我们以原始服务器为根将其转化成一个有根树,则深度不超过k的节点都已经被原始服务器覆盖。
我们选择深度最大的节点u然后将它的k级祖先设为服务器,进行一次DFS,将所有距离它不超过k的节点覆盖。
表示:
图的表示在这里面是用邻接表来表示的,如果a、b两个节点相邻,则gr[a]中放入b,gr[b]中放入a
怎样才算转化为有根树了?那就是把每个节点的爸爸(father)算出来,记录在fa数组中
试想,如果深度大于k的节点都已被覆盖,那么其他非叶子节点也一顶被覆盖了
所以将深度大于k的节点放在nodes表中
1 //#define LOCAL 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn = 1000 + 10; 9 vector<int> gr[maxn], nodes[maxn]; 10 int n, s, k, fa[maxn]; 11 bool coverd[maxn]; 12 13 void DFS(int u, int f, int d) 14 {//计算各个节点的祖先,放在fa数组中 15 fa[u] = f; 16 int nc = gr[u].size(); 17 if(nc == 1 && d > k) 18 nodes[d].push_back(u); 19 for(int i = 0; i < nc; ++i) 20 { 21 int v = gr[u][i]; 22 if(v != f) 23 DFS(v, u, d + 1); 24 } 25 } 26 27 void DFS2(int u, int f, int d) 28 { 29 coverd[u] = true; 30 int nc = gr[u].size(); 31 for(int i = 0; i < nc; ++i) 32 { 33 int v = gr[u][i]; 34 if(v != f && d < k) 35 DFS2(v, u, d + 1); 36 } 37 } 38 39 int solve(void) 40 { 41 int ans = 0; 42 memset(coverd, false, sizeof(coverd)); 43 for(int d = n - 1; d > k; --d) 44 for(int i = 0; i < nodes[d].size(); ++i) 45 { 46 int u = nodes[d][i]; 47 if(coverd[u]) continue; 48 49 int v = u; 50 for(int i = 0; i < k; ++i) //v是u的k级祖先 51 v = fa[v]; 52 DFS2(v, -1, 0); 53 ++ans; 54 } 55 return ans; 56 } 57 58 int main(void) 59 { 60 #ifdef LOCAL 61 freopen("3902in.txt", "r", stdin); 62 #endif 63 64 int T; 65 scanf("%d", &T); 66 while(T--) 67 { 68 scanf("%d%d%d", &n, &s, &k); 69 for(int i = 1; i <= n; ++i) 70 { 71 gr[i].clear(); 72 nodes[i].clear(); 73 } 74 for(int i = 0; i < n - 1; ++i) 75 { 76 int a, b; 77 scanf("%d%d", &a, &b); 78 gr[a].push_back(b); 79 gr[b].push_back(a); 80 } 81 DFS(s, -1, 0); 82 printf("%d ", solve()); 83 } 84 return 0; 85 }