zoukankan      html  css  js  c++  java
  • POJ3342 Party at HaliBula(树形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页)

  • 相关阅读:
    js循环
    js对象
    实现checkebox全选取消操作
    js数组
    jquery记忆笔记
    js选择checkbox值,组织成key-value形式,传值到后台
    ES6常用语法,面试应急专用!
    Win10 系统运行VsCode出现白屏的问题(亲测有效)
    command failed: npm install --loglevel error --registry=https://registry.npm 用vue-cli 4.0 新建项目总是报错
    MODULE BUILD FAILED: ERROR: COULDN’T FIND PRESET “ES2015” RELATIVE TO DIRECTORY
  • 原文地址:https://www.cnblogs.com/tanhehe/p/3134672.html
Copyright © 2011-2022 走看看