LA3902树形网络递归

经典题,需要温习。

题目链接:点击这里

总体思路

  1. 此题是网络结构,好久没做过这种题了。需要注意的是,这里有n个点,只有n-1条边,一定是无环图。因此,此题是无根树。
  2. 处理无根树比较麻烦,我们只知道一台server的编号,可以从这个server出发进行DFS,找到在其k距离范围内能达到的叶子节点(client)。但接下来怎么做呢?如何找到剩余叶子节点的最小server数呢?
  3. 因此,可以将无根树转化为有根数,就把server当作根节点,第一次DFS找到可以到达的所有叶子节点,然后从深度最深的叶子节点出发,找到其k祖先,将其设置为server,很容易证明这样是最省的。

代码实现

  • 思路不是很难想,但代码上需要有些技巧。

树的构建

  • 我们知道,可以使用邻接矩阵来构建,但在无向图中太浪费空间,并且此题n最大可以去1000,会造成内存溢出。
  • 因此我们可以采用邻接链表的形式,由于此题只有编号没有其他信息,因此可构建树vector<int> nodes[maxn];
  • 如何快速的找到其k个祖先呢?这里使用了一个数组进行存储其父节点,需要注意的是,由于此题是无向图,因此要注意方向,不然会造成死循环。

示例代码

  • 由于深度不超过k的叶子节点已经被服务器覆盖了,因此我们存储深度的时候,只存储深度大于k的节点,使用DFS来覆盖。

    
    #include <iostream>
    
    
    #include <vector>
    
    
    #include <set>
    
    
    #include <string.h>
    
    
    using namespace std;
    
    int N;       /* numbers of node */
    int n, s, k; /* n is the nodes, s is server,k is distance */
    
    const int maxn = 1000 + 10; /* max nodes */
    
    vector<int> nodes[maxn];
    
    vector<int> depth[maxn];
    
    bool covered[maxn];
    
    int fa[maxn];
    
    void get_father(int point, int father, int dis)
    {
      fa[point] = father;
      int num = nodes[point].size();
      if (num == 1 && dis > k)
          /* if point is client and depth >k , store the depth*/
          depth[dis].push_back(point);
      for (int i = 0; i < num; i++)
      {
          int child = nodes[point][i];
          if (child != father)
              get_father(child, point, dis + 1);
      }
    }
    
    /* set server on point */
    void dfs(int point, int father, int dis)
    {
      covered[point] = true;
      int num = nodes[point].size();
      for (int i = 0; i < num; i++)
      {
          int child = nodes[point][i];
          /* be careful child != father */
          if (child != father && dis < k)
              dfs(child, point, dis + 1);
      }
    }
    
    int solve()
    {
      int ans = 0;
      memset(covered, 0, sizeof(covered));
      for (int d = n - 1; d > k; d--)
      {
          for (int i = 0; i < depth[d].size(); i++)
          {
              int point = depth[d][i];
              if (covered[point])
                  continue;
              int temp = point;
              /* find dis = k father */
              for (int j = 0; j < k; j++)
                  temp = fa[temp];
    
              dfs(temp, -1, 0);
              ans++;
          }
      }
      return ans;
    }
    
    int main()
    {
      int kcase;
    
      cin >> kcase;
      for (int kk = 1; kk <= kcase; kk++)
      {
          cin >> n >> s >> k;
          for (int i = 1; i <= n; i++)
          {
              nodes[i].clear();
              depth[i].clear();
          }
    
          for (int i = 1; i < n; i++)
          {
              int a, b;
              cin >> a >> b;
              nodes[a].push_back(b);
              nodes[b].push_back(a);
          }
          get_father(s, -1, 0);
          cout << solve() << endl;
      }
      return 0;
    }
    

猜你喜欢

转载自blog.csdn.net/crazy_scott/article/details/80085802
LA
今日推荐