[hihocoder1055]刷油漆

来源:互联网 发布:淘宝客qq群怎么加人 编辑:程序博客网 时间:2024/04/28 15:30

问题描述

给树中每个节点赋予一个value,求包含指定节点的最多还有M个节点的一个联通的最大值。
具体参考hihocoder官网。

算法详解

1. 算法框架

子问题为求以该节点为根节点的子树中最多含有0-m个节点能够得到的最大值,递归实现的算法,每个节点内部利用动态规划求解。

递归基:如果没有子节点,那么max_value[0] = 0; max_value[1] = Node.value

每个节点内部:先求每个子节点的子问题的解,然后利用所有子节点的解求解本节点,其中利用了动态规划。

2. 动态规划求解子问题

通过对于每个子节点的子问题求解,可以得到以每个子节点为根节点的子树中最多含有0-m-1个节点且联通的最大值。
把每个子节点看做一个物品,对于物品i(i大于等于0,小于子节点数),如果花j块钱(j大于等于0,小于m),可以得到v_ij的价值;求如果总共有m块钱,如何购买,可以得到最大的价值。上诉问题是个典型的背包问题,对于物品进行枚举,每件物品枚举所花钱数,即可求解。对于所有节点的总时间复杂度为O(N*M*M)~10^6.
    void cal_value(int M) {//        cout << num << endl;        max_value[0] = 0;        max_value[1] = value;        int len = next.size();        if (len == 0)            return;        for (list<Node*>::iterator iter = next.begin();iter != next.end();++iter)            (*iter)->cal_value(M-1);        int values[101] = {0},tmp_max = 0;        for (list<Node*>::iterator iter = next.begin();iter != next.end();++iter){            for (int m = M-1;m > 0;--m){                tmp_max = values[m];                for (int i = m;i > 0;--i){                    if (values[m-i]+(*iter)->max_value[i] > tmp_max)                        tmp_max = values[m-i]+(*iter)->max_value[i];                }                values[m] = tmp_max;            }        }        for (int i = M;i > 1;--i)            max_value[i] = values[i-1]+value;    }

3. 构建树

这部分是用于去除子节点到父节点的边。
    void build_tree() {        list<Node*>::iterator iter;        for (iter = next.begin();iter != next.end();++iter) {            (*iter)->next.remove(this);            (*iter)->parent = this;            (*iter)->build_tree();        }    }

全部代码

#include <iostream>#include <list>using namespace std;struct Node{    static int cnt;    int num,value,max_value[101];    list<Node*> next;    Node* parent;    Node():num(cnt++),value(-1),parent(NULL) {}    Node (const Node &n):num(n.num),value(n.value),next(n.next),parent(n.parent) {}    ~Node() {}    void build_tree() {        list<Node*>::iterator iter;        for (iter = next.begin();iter != next.end();++iter) {            (*iter)->next.remove(this);            (*iter)->parent = this;            (*iter)->build_tree();        }    }    void cal_value(int M) {//        cout << num << endl;        max_value[0] = 0;        max_value[1] = value;        int len = next.size();        if (len == 0)            return;        for (list<Node*>::iterator iter = next.begin();iter != next.end();++iter)            (*iter)->cal_value(M-1);        int values[101] = {0},tmp_max = 0;        for (list<Node*>::iterator iter = next.begin();iter != next.end();++iter){            for (int m = M-1;m > 0;--m){                tmp_max = values[m];                for (int i = m;i > 0;--i){                    if (values[m-i]+(*iter)->max_value[i] > tmp_max)                        tmp_max = values[m-i]+(*iter)->max_value[i];                }                values[m] = tmp_max;            }        }        for (int i = M;i > 1;--i)            max_value[i] = values[i-1]+value;    }};int Node::cnt = 1;Node nodes[101];int main(){    int N,M;    int A,B;    cin >> N >> M;    for (int i = 0;i < N;++i)        cin >> nodes[i].value;    for (int i = 1;i < N;++i) {        cin >> A >> B;        nodes[A-1].next.push_back(nodes+B-1);        nodes[B-1].next.push_back(nodes+A-1);    }    nodes[0].build_tree();    nodes[0].cal_value(M);    cout << nodes[0].max_value[M] << endl;    return 0;}



0 0