UVa 1220——树形dp

题目来源:https://vjudge.net/problem/UVA-1220

题目描述:紫书上树形dp的第二个例题,在树的最大独立子集上加上了一个判断唯一性。所以两个同时dp即可,转移方法如下:

对于最大独立子集:

1.dp[u][1]表示选了u这个节点,则子节点不能选,dp[u][1]+=dp[v][0];

2.dp[u][0]表示没选u这个节点,那么子节点可选可不选,取其中最大的即可,dp[u][0]+=max(dp[v][1],dp[v][0])

对于唯一性判断,用f[i][j]表示,f[u][0]=0表式唯一,f[u][1]表示不唯一,转移有下两个式子

1.当且仅当u的子节点f[v][0]=1全部成立时,f[u][1]才是1;

2.如果某个dp[v][0]==dp[v][1],则不唯一;如果max取到的对应的f为0,方案也不唯一,如dp[v][0]>dp[v][1],且f[v][0]=0

这样,套用最大独立子集的模板,加上f数组判断,就能实现递推了,。

细节看代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;

/*
    注意f的转移方式,有两种:
    1.当且仅当所有子节点的f[v][0]=0时,f[root][0]=0(这里的0表示唯一)
    2.如果出现子节点dp[v][0]==dp[v][1],则f[root][0]=0
*/

const int maxn=205;
vector<int>G[maxn];
int n;
int dp[maxn][2];//表示选或不选
int f[maxn][2];//表示是否唯一
map<string,int>mp;
string s1,s2;
void init()
{
    for(int i=0;i<maxn;i++)G[i].clear();
    memset(dp,0,sizeof(dp));
    memset(f,0,sizeof(f));
    mp.clear();
}

void dfs(int root)
{

    if(G[root].size()==0)
    {
        dp[root][0]=0;
        dp[root][1]=1;
        return;
    }
    int size=G[root].size();
    for(int i=0;i<size;i++)
    {
        int v=G[root][i];
        dfs(v);
        if(f[v][0]==1)//子节点不唯一,父节点绝对不唯一
            f[root][1]=1;
        dp[root][1]+=dp[v][0];//这一层选了,儿子层都不能选
        if(dp[v][0]>dp[v][1])
        {
            dp[root][0]+=dp[v][0];
            if(f[v][0]==1)
                f[root][1]=1;
        }
        else
        {
            dp[root][0]+=dp[v][1];
            if(dp[v][1]==dp[v][0]||f[v][1])//两者相等也是不唯一的另一个条件
                f[root][0]=1;
        }
    }
    dp[root][1]++;
}

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)break;
        init();
        cin>>s1;
        int top=0;
        mp[s1]=top++;
        for(int i=1;i<=n-1;i++)
        {
            cin>>s1>>s2;
            if(mp.find(s1)==mp.end())
                mp[s1]=top++;
            if(mp.find(s2)==mp.end())
                mp[s2]=top++;
            G[mp[s2]].push_back(mp[s1]);
        }
        dfs(0);
        if(dp[0][1]==dp[0][0])
        {
            printf("%d No\n",dp[0][1]);
        }
        else if(dp[0][1]>dp[0][0])
        {
            printf("%d ",dp[0][1]);
            if(f[0][1])
                printf("No\n");
            else
                printf("Yes\n");
        }
        else
        {
            printf("%d ",dp[0][0]);
            if(f[0][0])
                printf("No\n");
            else
                printf("Yes\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Q755100802/article/details/83149200