HDOJ-1011(树形DP)

来源:互联网 发布:联网监控软件 编辑:程序博客网 时间:2024/06/07 22:54

容易想到状态方程:f[i][j] = max(f[i][j], f[child[i][k] + f[i][j - k]), 但一开始没有注意到很多细节,WA了几次之后看了discuss之后才了解:

(0)有些节点不需要留下trooper,但我们仍然需要派遣至少1个trooper去这些节点

(1)我们必须先攻克父节点才能进入子节点(必须在父节点留够充分的troopers才能进入下一个节点)

(2)进入子节点的时候我们必须携带至少1个的troopers,尽管一些节点并不需要留下trooper

下面是标准的读入、建树、DP过程:


#include <cstdio>#include <cstring>#include <vector>#include <algorithm>using namespace std;int N, M;struct Node{    int cost, gain;    vector<int> children;} arr[101];//tree structureint gain[101][101];//best[i][j] is for subtree with root being node i,                   //with j money in total, how many gains we can getvector<int> tmp[101];//temporary save of bidirectional connectionsbool vis[101];       //visited flags of each nodevoid buildTree(int i){    vis[i] = true;    const vector<int>& v = tmp[i];    for(int k = 0, s = v.size(); k < s; ++k){        int adj = v[k];        if(vis[adj]) continue;        arr[i].children.push_back(adj);        buildTree(adj);    }}bool input(){    scanf("%d %d", &N, &M);    if(N < 0) return false;//input node info    for(int i = 1; i <= N; ++i){        scanf("%d %d", &arr[i].cost, &arr[i].gain);        int q = arr[i].cost / 20;        if(arr[i].cost % 20) arr[i].cost = q + 1;        else arr[i].cost = q;    //initialize        vis[i] = false;        tmp[i].clear();        arr[i].children.clear();        memset(gain[i], 0, (M + 1) << 2);    }//input connection info    int from, to;    for(int i = 1; i < N; ++i){        scanf("%d %d", &from, &to);        tmp[from].push_back(to);        tmp[to].push_back(from);    }//build tree start from 1    buildTree(1);    return true;}void postDP(int i){    const vector<int>& v = arr[i].children;    int child, money, j, k = 0, s = v.size();//before traverse to subtrees    for(money = arr[i].cost; money <= M; ++money) gain[i][money] = arr[i].gain;//post traverse    for(; k < s; ++k){        child = v[k];        postDP(child);        //zero one pack with child v[k]        //we need to leave enough money to pay for this gate        for(money = M; money >= arr[i].cost; --money){            //this gate may take no money, and we must take at least 1 unit to next gate            for(j = 1; j <= money - arr[i].cost; ++j){                gain[i][money] = max(gain[i][money],                                     gain[child][j] + gain[i][money - j]                                    );            }        }    }}int main(){    while(input()){        if(M == 0){            puts("0");            continue;        }        postDP(1);        printf("%d\n", gain[1][M]);    }    return 0;}
但实际上我们并不需要明确的建树过程:


#include <cstdio>#include <cstring>#include <vector>#include <algorithm>using namespace std;int N, M;struct Node{    int cost, gain;    vector<int> children;} arr[101];//tree structureint gain[101][101];//best[i][j] is for subtree with root being node i,                   //with j money in total, how many gains we can getbool vis[101];bool input(){    scanf("%d %d", &N, &M);    if(N < 0) return false;//input node info    for(int i = 1; i <= N; ++i){        scanf("%d %d", &arr[i].cost, &arr[i].gain);        int q = arr[i].cost / 20;        if(arr[i].cost % 20) arr[i].cost = q + 1;        else arr[i].cost = q;    //initialize        vis[i] = false;        arr[i].children.clear();        memset(gain[i], 0, (M + 1) << 2);    }//input connection info    int from, to;    for(int i = 1; i < N; ++i){        scanf("%d %d", &from, &to);        arr[from].children.push_back(to);        arr[to].children.push_back(from);    }    return true;}void postDP(int i){    vis[i] = true;    const vector<int>& v = arr[i].children;    int child, money, j, k = 0, s = v.size();//before traverse to subtrees    for(money = arr[i].cost; money <= M; ++money) gain[i][money] = arr[i].gain;//post traverse    for(; k < s; ++k){        child = v[k];        if(vis[child]) continue;        postDP(child);        //zero one pack with child v[k]        //we need to leave enough money to pay for this gate        for(money = M; money >= arr[i].cost; --money){            //this gate may take no money, and we must take at least 1 unit to next gate            for(j = 1; j <= money - arr[i].cost; ++j){                gain[i][money] = max(gain[i][money],                                     gain[child][j] + gain[i][money - j]                                    );            }        }    }}int main(){    while(input()){        if(M == 0){            puts("0");            continue;        }        postDP(1);        printf("%d\n", gain[1][M]);    }    return 0;}

虽然A了,但是感觉好奇怪,明明空间和时间都需要的少了,judge的时候反而比前面的程序需要更多的空间和时间……

0 0
原创粉丝点击