POJ3342 Party at Hali-Bula(树形DP)

题目链接

题意:

给定一个树,选择若干点,使得选择的结点中任一结点不会和它的子结点同时选择,求能选结点最大数量。同时判断方案数是否为一。

分析:

如果单单求最大数量,很容易。之前也做过一个。链接:http://www.cnblogs.com/tanhehe/archive/2013/06/12/3132521.html

但是如何判断方案数是否唯一呢?

新加一个状态 dup[i][j],表示相应 dp[i][j] 是否唯一方案。

对于叶子结点,dup[k][0] = dup[k][1] = 1.

对于非叶子结点,

  1.对于 i 的任意儿子 j, 若(dp[j][0] > dp[j][1] 且 dup[j][0] == 0) 或 (dp[j][0] < dp[j][1] 且 dup[j][1] == 0) 或 (dp[j][0] == dp[j][1]), 则 dup[i][0] = 0.

  2.对于 i 的r任意儿子 j 有 dup[j][0] = 0, 则 dup[i][1] = 0。

 

在这里,左儿子右兄弟的写法。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>

using namespace std;

const int maxn = 200 + 10;

bool dup[maxn][2];

struct Tree {
    int child, brother, father;
    int Take, Not;

    void init() {
        child = brother = father = Not = 0;
        Take = 1;
    }
}tree[maxn];

void dfs(int idx) {
    int child = tree[idx].child;

    while(child) {
        dfs(child);

        tree[idx].Take += tree[child].Not;
        tree[idx].Not += max(tree[child].Take, tree[child].Not);

        if((tree[child].Take > tree[child].Not && dup[child][1] == false) ||
           (tree[child].Take < tree[child].Not && dup[child][0] == false) ||
           (tree[child].Take == tree[child].Not))
            dup[idx][0] = false;

        if(dup[child][0] == false) dup[idx][1] = false;

        child = tree[child].brother;
    }
}

int main() {
    int n;
    char s1[100+10], s2[100+10];

    while(scanf("%d", &n) == 1 && n) {
        int cnt = 0;
        map<string, int> a;

        for(int i=1; i<=n; i++) {
            tree[i].init();
        }

        scanf("%s", s1);
        a[s1] = ++cnt;

        for(int i=2; i<=n; i++) {
            scanf("%s%s", s1, s2);

            if(a.count(s1) == 0) a[s1] = ++cnt;
            int d1 = a[s1];
            if(a.count(s2) == 0) a[s2] = ++cnt;
            int d2 = a[s2];

            tree[d1].father = d2;
            tree[d1].brother = tree[d2].child;
            tree[d2].child = d1;
        }

        memset(dup, true, sizeof(dup));

        dfs(1);

        printf("%d ", max(tree[1].Take, tree[1].Not));

        if((tree[1].Take > tree[1].Not && dup[1][1] == false)   ||
           (tree[1].Take < tree[1].Not && dup[1][0] == false)   ||
           tree[1].Take == tree[1].Not)
           printf("No\n");
        else printf("Yes\n");
    }
}
View Code

 

或者直接建树,写法差不多:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>

using namespace std;

const int maxn = 200 + 10;

struct Node {
    int from, to, next;
}edges[maxn];

int n, mem, head[maxn];
int dp[maxn][2];
bool dup[maxn][2];

void init() {
    mem = 0;
    memset(head, -1, sizeof(head));
}

void AddEdge(int u, int v) {
    edges[mem].from = u;
    edges[mem].to = v;
    edges[mem].next = head[u];
    head[u] = mem++;
}

void dfs(int idx) {
    dp[idx][0] = 0;
    dp[idx][1] = 1;
    dup[idx][0] = dup[idx][1] = true;

    for(int i=head[idx]; i != -1; i = edges[i].next) {
        int v = edges[i].to;
        dfs(v);

        dp[idx][0] += max(dp[v][0], dp[v][1]);
        dp[idx][1] += dp[v][0];

        if((dp[v][0] > dp[v][1] && !dup[v][0]) ||
           (dp[v][0] < dp[v][1] && !dup[v][1]) ||
           dp[v][0] == dp[v][1])
           dup[idx][0] = false;
        if(!dup[v][0]) dup[idx][1] = false;
    }
}

int main() {
    char s1[100+10], s2[100+10];

    while(scanf("%d", &n) == 1 && n) {
        map<string, int> a;
        init();
        int cnt = 0;

        scanf("%s", s1);

        a[s1] = ++cnt;

        for(int i=1; i<n; i++) {
            scanf("%s %s", s1, s2);

            if(a.count(s1) == 0) a[s1] = ++cnt;
            if(a.count(s2) == 0) a[s2] = ++cnt;

            AddEdge(a[s2], a[s1]);
        }

        dfs(1);

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

        if((dp[1][1] > dp[1][0] && !dup[1][1]) ||
           (dp[1][1] < dp[1][0] && !dup[1][0]) ||
           dp[1][0] == dp[1][1])
           printf("No\n");
        else printf("Yes\n");
    }
}
View Code

 

 

分析参考:http://wenku.baidu.com/view/aee323cd0508763231121252.html(第8页)

posted on 2013-06-13 21:06  Still_Raining  阅读(209)  评论(0编辑  收藏  举报