UVa #1220 Party at Hali-Bula (例题9-13)

来源:互联网 发布:数据库有5个事务 编辑:程序博客网 时间:2024/06/10 10:13

新年第一题,一道树上的动态规划,树的最大独立集问题。


书中介绍最大独立集时提到了刷表法,却说有一种更实用的方法将在例题中介绍,应该说的就是这题。


按照这种方法的思路,我们不必枚举所有儿子和所有孙子,只需要加一个维度来表示是否选中当前节点然后只枚举儿子。


对于已经选中的节点,在记忆化搜索的递归时,将它所有儿子的这个维度设为“不选中”即可。

对于不选中的节点,则对于每个儿子,分别求出选中/不选中的dp值,然后选取较大者即可。


对于这道题的特殊要求:唯一性,书里用 f=1 表示“唯一”,f=0 表示“不唯一”,其实不太方便。因为对于某一个节点,只有他的全部儿子节点都唯一时,他自己才唯一。所以不如把 f 的用法调转,这样只要碰到不唯一的儿子,这个节点就可以设置成“不唯一”了。



Run Time: 0.035s

#define UVa  "LT9-13.1220.cpp"//Party at Hali-Bulachar fileIn[30] = UVa, fileOut[30] = UVa;#include<cstring>#include<cstdio>#include<algorithm>#include<vector>#include<map>#include<iostream>#include<string>using namespace std;//Global Variables. Reset upon Each Case!const int maxn = 200 + 10;int n;vector<int> S[maxn];map<string, int> Names;int d[maxn][2];int dup[maxn][2];/////int dp(int u, int f) {    if(d[u][f]) return d[u][f];    if(S[u].size() == 0) {      //leaf node.        d[u][f] = f;    }    else {                      //internal node.        if(f == 1) {        //node selected.            d[u][f] = 1;            for(int i = 0; i < S[u].size(); i ++) {                d[u][f] += dp(S[u][i], 0);                if(dup[S[u][i]][0]) dup[u][f] = 1;            }        }        else {              //node not selected.            d[u][f] = 0;            for(int i = 0; i < S[u].size(); i ++) {                int a = dp(S[u][i], 0), b = dp(S[u][i], 1), c = max(a,b);                d[u][f] += c;                if( a == b                    || (a > b && dup[S[u][i]][0])                    || (a < b && dup[S[u][i]][1])                   ) dup[u][f] = 1;            }        }    }    return d[u][f];}void init() {    for(int i = 0; i < maxn; i ++) S[i].clear();    Names.clear();    memset(d, 0, sizeof(d));    memset(dup, 0, sizeof(dup));    string tmp, tmpboss;    int cnt = 0;    cin>>tmp;    Names[tmp] = cnt++;    for(int i = 1; i < n; i ++) {        cin>>tmp>>tmpboss;        int a, b;        if(!Names.count(tmp))            a = Names[tmp] = cnt ++;        else            a = Names[tmp];        if(!Names.count(tmpboss))            b = Names[tmpboss] = cnt ++;        else            b = Names[tmpboss];        S[b].push_back(a);    }}int main() {    while(scanf("%d", &n) && n) {        init();        int a = dp(0,0), b = dp(0,1);        if(a == b)            dup[0][0] = dup[0][1] = 1;        if(a > b)            printf("%d %s\n", a, (dup[0][0])?"No":"Yes");        else            printf("%d %s\n", b, (dup[0][1])?"No":"Yes");    }    return 0;}


0 0