UVA-1218PerfectService题意有n台电脑。互相以无根树的方式连接,现要将当中一部分电脑作为server,且要求每台电脑必须连接且仅仅能连接一台server(不包含作为server的电脑)。求最少须要多少台电脑作为server。思路典型的树形dp问题,那么我们来建立模型。d(u,0):u是server,孩子是不是server均可d(u,1):u不是se"/>

UVA - 1218 Perfect Service(树形dp)

Posted slgkaifa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVA - 1218 Perfect Service(树形dp)相关的知识,希望对你有一定的参考价值。

题目链接UVA - 1218 Perfect Service

题意

有n台电脑。互相以无根树的方式连接,现要将当中一部分电脑作为server,且要求每台电脑必须连接且仅仅能连接一台server(不包含作为server的电脑)。求最少须要多少台电脑作为server。

思路

典型的树形dp问题,那么我们来建立模型。
d(u,0):u是server,孩子是不是server均可
d(u,1):u不是server,u的父亲是server,u的孩子不能是server
d(u,2):u不是server且u的父亲不是server,u的孩子必须有且仅有一个是server。

那么显然的
d(u,0) = 1 + Sum( Min(d(v,1), d(v,0)) ) |v是u的孩子
d(u,1) = Sum(d(v,2))
d(u,2)稍复杂些。由于仅仅能有一个孩子是server,所以须要遍历每一个孩子为server的情况,每一轮遍历都要同一时候计算其它全部孩子,须要O(N^2)的时间。
显然这样会有非常多反复计算的情况,当然能够记忆化来加高速度,可是另一个更快的小技巧。由于d(u,1)和d(u,2)的唯一差别就是d(u,2)的孩子有一个server
那么我们能够得出
d(u,2) = Min(d(u,1)-d(v,2)+d(v,0)) |v是u的孩子
仍是遍历设每一个孩子为server。每一轮的操作为O(1),整体为O(N)

代码

ps:由于d(u,2)初始要设为无穷大,就设了0x3f3f3f3f,结果改成N就好了,找了好久才找出问题出在这,由于这个wrong了好多遍,但还是不知道为什么会wrong,知道原因的道友请不吝指点。

第一遍a的代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <cmath>
#include <map>

using namespace std;

const int N = 10009;
vector<int> g[N];
int dp[N][3];

void dfs(int u, int fa)
{
    for(int i=0; i<g[u].size(); i++)
    {
        if(g[u][i] != fa)
            dfs(g[u][i], u);
    }
    dp[u][0] = 1;
    dp[u][1] = 0;
    dp[u][2] = N;
    for(int i=0; i<g[u].size(); i++)
    {
        if(g[u][i] != fa)
        {
            dp[u][0] += min(dp[g[u][i]][0], dp[g[u][i]][1]);
            dp[u][1] += dp[g[u][i]][2];
        }
    }
    bool f = true;
    for(int i=0; i<g[u].size(); i++)
    {
        if(g[u][i] != fa)
        {
            f = false;
            dp[u][2] = min(dp[u][2], dp[u][1]+dp[g[u][i]][0]-dp[g[u][i]][2]);
        }
    }
}

int main()
{
    int n;
    while(cin>>n)
    {
        memset(dp, -1, sizeof(dp));
        int a, b;
        for(int i=1; i<n; i++)
        {
            cin>>a>>b;
            g[a].push_back(b);
            g[b].push_back(a);
        }
        dfs(1, -1);
        cout<<min(dp[1][0], dp[1][2])<<endl;

        cin>>a;
        if(a == -1)
            break;
        for(int i=1; i<=n; i++)
            g[i].clear();
    }
    return 0;
}

观摩大神代码后进行改动的精简版

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <cmath>
#include <map>

using namespace std;

const int N = 10009;
vector<int> g[N];
int dp[N][3];

void dfs(int u, int fa)
{
    dp[u][0] = 1;
    dp[u][1] = 0;
    dp[u][2] = N;
    for(int i=0; i<g[u].size(); i++)
    {
        if(g[u][i] != fa)
        {
            dfs(g[u][i], u);
            dp[u][0] += min(dp[g[u][i]][0], dp[g[u][i]][1]);
            dp[u][1] += dp[g[u][i]][2];
        }
    }

    for(int i=0; i<g[u].size(); i++)
    {
        if(g[u][i] != fa)
            dp[u][2] = min(dp[u][2], dp[u][1]+dp[g[u][i]][0]-dp[g[u][i]][2]);
    }
}

int main()
{
    int n;
    while(cin>>n)
    {
        int a, b;
        for(int i=1; i<n; i++)
        {
            cin>>a>>b;
            g[a].push_back(b);
            g[b].push_back(a);
        }
        dfs(1, -1);
        cout<<min(dp[1][0], dp[1][2])<<endl;

        cin>>a;
        if(a == -1)
            break;
        for(int i=1; i<=n; i++)
            g[i].clear();
    }
    return 0;
}

以上是关于UVA - 1218 Perfect Service(树形dp)的主要内容,如果未能解决你的问题,请参考以下文章

Perfect Service UVA - 1218(树形dp)

UVA - 1218 Perfect Service(树形dp)

[UVA-1218] Perfect Service(树的最小支配集)

uva1218 Perfect Service

UVA-1220-Party at Hali-Bula && UVA-1218-Perfect Service(树形DP)

UVA - 10622 Perfect P-th Powers