9-13 树的最大独立集

p280 9.4.2

原问题d(i)是以i为根节点,子问题是以i的儿子节点和以i的孙子节点为根节点。

讲解中的“当计算出一个d(i)后,用它去更新i的父亲和祖父节点的累加值”,对应到代码,需要从树的叶子节点开始计算d(i),可以用dfs

下面是 poj 2342的代码,例题9-13 UVa 1220 对应 poj 3342

#define _CRT_SECURE_NO_WARNINGS

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

int N;// 1 <= N <= 6000;
const int maxn = 6000;
// d[u][0]表示当不选前节点u,能获得的最大conviviality rating
// d[u][1]表示当选择前结点u,能获得的最大conviviality rating
int d[maxn + 5][2];
int visit[maxn + 5][2]; // d[u][k] already calculated

// the supervisor relation forms a tree
int parent[maxn + 5];
int root;

vector<int> sons[maxn + 5]; // sons of a parent

// d[u][k], k==1 or k==0
// depth first search
int dp(int u, int k) 
{
    if (visit[u][k] > 0)
        return d[u][k];

    if (k == 0)
        d[u][0] = 0;

    for (int j = 0; j < sons[u].size(); j++) { // for each son of vertex u
        int v = sons[u][j];
        
        if (k == 1) { // select u, not select v
            d[u][1] += dp(v,0); // dfs
        }
        else { // not select u, select or not select v
            d[u][0] += max(dp(v, 1), dp(v, 0)); // dfs
        }
    }

    visit[u][k] = 1;
    return d[u][k];
}

int main()
{
    while (scanf("%d", &N) != EOF){

        memset(d, 0, sizeof(d));
        memset(visit, 0, sizeof(visit));
        memset(parent, 0, sizeof(parent));
        for (int i = 1; i <= N; i++)
            sons[i].clear();

        for (int i = 1; i <= N; i++)
            scanf("%d", &d[i][1]);

        for (int i = 1; i <= N; i++){
            int L, K;
            scanf("%d%d", &L, &K);
            if (L == 0 && K == 0) // end of input
                break;
            parent[L] = K;
            sons[K].push_back(L);
        }

        for (int i = 1; i <= N; i++){
            if (parent[i] == 0){
                root = i;
                break;
            }
        }

        printf("%d\n", max(dp(root, 0), dp(root, 1)));
    }

    return 0;
}

 例题 9-13 对应 poj 3342

#define _CRT_SECURE_NO_WARNINGS

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

int n;// 1 <= n <= 200;
const int maxn = 200;
int cnt; // 节点的编号,从1开始

// d[u][0]表示当不选前节点u,能获得的最大个数
// d[u][1]表示当选择前结点u,能获得的最大个数
int d[maxn + 5][2];
int visit[maxn + 5][2]; // d[u][k] & f[u][k] already calculated

// f[u][0]表示当不选前节点u,是否唯一
// f[u][1]表示当选择前结点u,是否唯一
int f[maxn + 5][2];

int root;
vector<int> sons[maxn + 5]; // sons of a parent
map<string, int> dict; // name string --> vertex id

int nameToId(const string& str)
{
    if (dict.count(str) == 0){ // not exist
        dict[str] = cnt++;
    }

    return dict[str];
}

// compute d[u][k] & f[u][k], k==1 or k==0
// depth first search
int dp(int u, int k)
{
    if (visit[u][k] > 0)
        return d[u][k];

    d[u][k] = k;
    f[u][k] = 1;

    for (int j = 0; j < sons[u].size(); j++) { // for each son of vertex u
        int v = sons[u][j];

        if (k == 1) { // select u, not select v
            d[u][1] += dp(v, 0); // dfs
            if (f[v][0] == 0) // if for any son v it's f[v][0] == 0 then f[u][1] == 0
                f[u][1] = 0;
        }
        else { // k == 0, not select u, select or not select v
            d[u][0] += max(dp(v, 1), dp(v, 0)); // dfs

            if (d[v][0] == d[v][1])
                f[u][k] = 0;
            else if (d[v][0] > d[v][1] && f[v][0] == 0) // select d[v][0]
                f[u][k] = 0;
            else if (d[v][1] > d[v][0] && f[v][1] == 0) // select d[v][1]
                f[u][k] = 0;
        }

    }

    visit[u][k] = 1;
    return d[u][k];
}

int main()
{
    while (scanf("%d", &n) != EOF && n){

        memset(d, 0, sizeof(d));
        memset(f, 0, sizeof(f));
        memset(visit, 0, sizeof(visit));

        for (int i = 1; i <= n; i++)
            sons[i].clear();

        cnt = 1;
        dict.clear();
        for (int i = 1; i <= n; i++){
            string s1, s2;
            int son, par;
            if (i == 1){
                cin >> s1;
                root = nameToId(s1);
            }
            else {
                cin >> s1 >> s2;
                son = nameToId(s1);
                par = nameToId(s2);
                sons[par].push_back(son);
            }
        }


        printf("%d ", max(dp(root, 0), dp(root, 1)));

        bool unique = false;
        if (d[root][0] > d[root][1] && f[root][0])
            unique = true;
        if (d[root][1] > d[root][0] && f[root][1])
            unique = true;
        if (unique) 
            printf("Yes\n"); 
        else 
            printf("No\n");

    }

    return 0;
}

 

posted @ 2016-09-08 15:04  PatrickZhou  阅读(1476)  评论(0编辑  收藏  举报