【题解】UVa 1218 Perfect Service

本文介绍了一种使用树形动态规划解决的问题,即如何在由若干机器组成的树状网络中部署最少数量的服务器,确保每台非服务器机器直接连接到一台服务器。通过定义不同状态,文章详细阐述了状态转移方程及其优化方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

UVa传送门
洛谷RemoteJudge传送门
题目大意:有n(n ≤ 10000)台机器组成树形结构,要求在其中的一些机器上安装服务器,使得每台不是服务器的计算机恰好和一台服务器计算器相连。求服务器最少的数量。
典型树形DP。
根据节点的情况进行分类。
d(u,0) d ( u , 0 ) : u u 是服务器,子节点是或不是服务器均可。
d(u,1): u u 不是服务器,但u的父亲是服务器,这意味着 u u 的所有儿子都不是服务器。
d(u,2): u u 不是服务器,而且u的父亲也不是服务器。这意味着 u u 的所有儿子结点中有且仅有一个儿子是服务器。
有了刚才的解释,状态转移方程写出来也不算复杂:
d(u,0)=min(d(v,0),d(v,1))+1
d(u,1)=d(v,2) d ( u , 1 ) = ∑ d ( v , 2 )
d(u,2)=d(v,0)+d(v,2) d ( u , 2 ) = d ( v , 0 ) + ∑ d ( v ′ , 2 )
枚举 v v v表示除了 v v 以外的u的子节点
由此看来,三种运算所需要的时间并不相同, d(u,2) d ( u , 2 ) 需要花 O(k2) O ( k 2 ) 的时间进行计算,时间复杂度过高,仔细观察状态其实我们可以利用已经被计算过的 d(u,1) d ( u , 1 ) 优化我们的状态转移方程。
d(u,1) d ( u , 1 ) 只需在所有 d(u,1)d(v,2)+d(v,0) d ( u , 1 ) – d ( v , 2 ) + d ( v , 0 ) 中取个 min m i n 即可。
这样子,三种状态都能在 O(k) O ( k ) 的时间内被计算,总的时间复杂度为 O(n) O ( n )

Code C o d e

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值