Perfect service(树形dp)

Perfect service(树形dp)

有n台机器形成树状结构,要求在其中一些机器上安装服务器,使得每台不是服务器的计算机恰好和一台服务器计算机相邻。求服务器的最小数量。n<=10000。

这种类似独立集的树形dp问题,都可以将同一个结点的状态分成几类。这里用\(f[i][0]\)表示i是服务器,\(f[i][1]\)表示i不是服务器,但是i的父亲是服务器。\(f[i][2]\)表示i和i的父亲都不是服务器。

那么就可以写出转移方程:\(f[i][0]=sum(min(f[v][0], f[v][1]))+1\)\(f[i][1]=sum(f[v][2])\)\(f[i][2]=min(f[i][1]-f[v][2]+f[v][0])\)。时间复杂度为\(O(n)\)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn=1e4+5;

int cntedge, fir[maxn];
struct Edge{
    int to, next;
}e[maxn];
void RESET(){ cntedge=0; memset(fir, 0, sizeof(fir)); }
void addedge(int x, int y){
    Edge &e1=e[++cntedge];
    e1.to=y; e1.next=fir[x]; fir[x]=cntedge;
}

int n, f[maxn][3];  //0:自己是 1:父亲是 2:自己和父亲都不是
\
//也可以保存访问顺序,在外部访问
void dfs(int u, int par){
    f[u][0]=1; f[u][1]=0;
    f[u][2]=n; int v;
    for (int i=fir[u]; i; i=e[i].next){
        if ((v=e[i].to)==par) continue;
        dfs(v, u);
        f[u][0]+=min(f[v][0], f[v][1]);
        f[u][1]+=f[v][2];
    }
    for (int i=fir[u]; i; i=e[i].next){
        if ((v=e[i].to)==par) continue;
        f[u][2]=min(f[u][2], f[u][1]-f[v][2]+f[v][0]);
    }
}

int main(){
    int t1=0, t2;
    while (~t1&&~scanf("%d", &n)){
        RESET();
        for (int i=1; i<n; ++i){
            scanf("%d%d", &t1, &t2);
            addedge(t1, t2); addedge(t2, t1); }
        dfs(1, 0);
        printf("%d\n", min(min(f[1][0], f[1][1]), f[1][2]));
        scanf("%d", &t1);
    }
    return 0;
}
posted @ 2018-04-17 15:46  pechpo  阅读(276)  评论(0编辑  收藏  举报