UVA - 1218 Perfect Service(树形dp)

题目链接:UVA - 1218 Perfect Service

题意

有n台电脑,互相以无根树的方式连接,现要将其中一部分电脑作为服务器,且要求每台电脑必须连接且只能连接一台服务器(不包括作为服务器的电脑),求最少需要多少台电脑作为服务器。

思路

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

那么显然的
d(u,0) = 1 + Sum( Min(d(v,1), d(v,0)) ) |v是u的孩子
d(u,1) = Sum(d(v,2))
d(u,2)稍复杂些,因为只能有一个孩子是服务器,所以需要遍历每个孩子为服务器的情况,每一轮遍历都要同时计算其他所有孩子,需要O(N^2)的时间。
显然这样会有很多重复计算的情况,当然可以记忆化来加快速度,但是还有一个更快的小技巧,因为d(u,1)和d(u,2)的唯一区别就是d(u,2)的孩子有一个服务器
那么我们可以得出
d(u,2) = Min(d(u,1)-d(v,2)+d(v,0)) |v是u的孩子
仍是遍历设每个孩子为服务器,每一轮的操作为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;
}

你可能感兴趣的:(dp)