(06-08補)UVALive 3902 Network 網絡

題目大意: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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章