POJ 3342 (树形DP)

题意 :给出一些上下级关系,要求i和i的直接上级不能同时出现,现在选出一些人构成一个集合,问你这个集合里面的最大人数是都少,同时给出这个最大的人数的集合是否唯一。

思路:树形DP,dp[i][0],表示以i为跟节点的子树,不取i时的最优解,dp[i][1]表示以i为跟节点的子树,取i时的最优解,再另设only数组,only[i][0]表示以i为跟节点的子树,不i时最  优解是否唯一,only[i][1]表示以i为跟节点取i时最优解是否唯一

#include<map>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 222
using namespace std;
typedef struct{
    int to, next;
}Edge;
Edge edge[MAXN];
int dp[MAXN][2], head[MAXN];
int only[MAXN][2], cnt;
void addEdge(int u, int v, int k){
    edge[k].to = v;
    edge[k].next = head[u];
    head[u] = k;
}
void dfs(int s){
    dp[s][0] = 0;
    dp[s][1] = 1;
    for(int i = head[s];~i;i = edge[i].next){
        int u = edge[i].to;
        dfs(u);
        if(dp[u][0] > dp[u][1]){
            dp[s][0] += dp[u][0];
            if(only[u][0]) only[s][0] = 1;
        }else if(dp[u][0] < dp[u][1]){
            dp[s][0] += dp[u][1];
            if(only[u][1]) only[s][0] = 1;
        }else{
            dp[s][0] += dp[u][0];
            only[s][0] = 1;
        }
        dp[s][1] += dp[u][0];
        if(only[u][0]) only[s][1] = 1;
    }
}
int main(){
    int n, k;
    string s1, s2;
    map<string, int>mp;
   // freopen("in.c", "r", stdin);
    while(~scanf("%d", &n) && n){
        mp.clear(), k = 1, cnt = 0;
        cin >> s1;
        mp[s1] = k++;
        memset(head, -1, sizeof(head));
        memset(only, 0, sizeof(only));
        for(int i = 1;i <= n-1; i++){
            cin >> s1 >> s2;
            if(mp.find(s1) == mp.end()) mp[s1] = k++;
            if(mp.find(s2) == mp.end()) mp[s2] = k++;
            addEdge(mp[s2], mp[s1], i);
        }
        addEdge(0, 1, n);
        dfs(0);
        printf("%d ", max(dp[1][0], dp[1][1]));
        if(!only[0][0]) printf("Yes
");
        else printf("No
");        
    }
    return 0;
}




原文地址:https://www.cnblogs.com/anhuizhiye/p/3933151.html