【題解】UVa 1218 Perfect Service

UVa傳送門
洛谷RemoteJudge傳送門
題目大意:有n(n ≤ 10000)臺機器組成樹形結構,要求在其中的一些機器上安裝服務器,使得每臺不是服務器的計算機恰好和一臺服務器計算器相連。求服務器最少的數量。
典型樹形DP。
根據節點的情況進行分類。
d(u,0) :u 是服務器,子節點是或不是服務器均可。
d(u,1) :u 不是服務器,但u 的父親是服務器,這意味着u 的所有兒子都不是服務器。
d(u,2) :u 不是服務器,而且u 的父親也不是服務器。這意味着u 的所有兒子結點中有且僅有一個兒子是服務器。
有了剛纔的解釋,狀態轉移方程寫出來也不算複雜:
d(u,0)=min(d(v,0),d(v,1))+1
d(u,1)=d(v,2)
d(u,2)=d(v,0)+d(v,2)
枚舉vv 表示除了v 以外的u 的子節點
由此看來,三種運算所需要的時間並不相同,d(u,2) 需要花O(k2) 的時間進行計算,時間複雜度過高,仔細觀察狀態其實我們可以利用已經被計算過的d(u,1) 優化我們的狀態轉移方程。
d(u,1) 只需在所有d(u,1)d(v,2)+d(v,0) 中取個min 即可。
這樣子,三種狀態都能在O(k) 的時間內被計算,總的時間複雜度爲O(n)

Code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#define MAXN 10010
std::vector< int > G[MAXN];
int d[MAXN][3];
void solve(int u, int p) {
    for (unsigned int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if (v == p) continue;
        solve(v, u);
        d[u][0] += std::min(d[v][0], d[v][1]);
        d[u][1] += d[v][2];
    }
    for (unsigned int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if (v == p) continue;
        d[u][2] = std::min(d[u][2], d[u][1] - d[v][2] + d[v][0]);
    }
}
int main() {
    int n;
    scanf("%d", &n);
    while (true) {
        for (int i = 1; i <= n; i++) {
            G[i].clear();
            d[i][0] = 1; 
            d[i][1] = 0;
            d[i][2] = MAXN;
        }
        for (int i = 1; i < n; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        solve(1, -1);
        printf("%d\n", std::min(d[1][0], d[1][2]));
        scanf("%d", &n);
        if (n == -1) break;
        scanf("%d", &n);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章