LA_3902 - Network

14 篇文章 0 订阅
題意:
一個樹狀網絡,指定一個服務器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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值