树状dp入门-poj2342-Anniversary party 题解

树状DP

        树状dp,一个问题我们能够转化成树这个数据结构,并且在其基础上使用dp。树这个数据结构本身就带有递归的性质,同时无环、分层,所以跟dfs有非常紧密的联系。那么我们利用深搜,配合dp的状态转移方程,就能够在树上非常自然地写出代码。

        树状dp是否能够构造的重要特点就是,父子关系是否满足dp的要求。当然首先要满足这个题可以使用dp来求解,这个是最基础的。如果父结点与孩子可以构造状态转移方程,那么我们才可以使用树状dp的思想。

        一般来说,我们是从叶子结点从下向上分析到根结点。对于无根树,我们可以通过遍历结点的方式,考虑每个结点都是根,从而进行操作。结点的储存就看情况了,邻接矩阵、邻接表都可以。为了利用树的结构,我们也可以用特殊的方式,例如数组储存结点,值储存父亲这样的方式。这样更方便利用递归(实际上是邻接矩阵)。在层层向上的过程中,要for循环遍历多次,所以容易超时,有剪枝的情况一定不能错过。

        下面是树状dp经典入门题,看懂的话就会对树状dp有一些理解了,毕竟这是一种思想,文字还是不太容易描述。

题目链接

poj-2342 Anniversary party

poj的数据貌似是单case,hdu有一样的题,使用cin或者其他写法的可能会TLE,所以推荐去hdu交一下这个题

hdu-1520 Anniversary party

题目

Anniversary party

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 11284 Accepted: 6502

Description

There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure of employees. It means that the supervisor relation forms a tree rooted at the rector V. E. Tretyakov. In order to make the party funny for every one, the rector does not want both an employee and his or her immediate supervisor to be present. The personnel office has evaluated conviviality of each employee, so everyone has some number (rating) attached to him or her. Your task is to make a list of guests with the maximal possible sum of guests' conviviality ratings.

Input

Employees are numbered from 1 to N. A first line of input contains a number N. 1 <= N <= 6 000. Each of the subsequent N lines contains the conviviality rating of the corresponding employee. Conviviality rating is an integer number in a range from -128 to 127. After that go N – 1 lines that describe a supervisor relation tree. Each line of the tree specification has the form: 
L K 
It means that the K-th employee is an immediate supervisor of the L-th employee. Input is ended with the line 
0 0 

Output

Output should contain the maximal sum of guests' ratings.

Sample Input

7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0

Sample Output

5

Source

Ural State University Internal Contest October'2000 Students Session

题意

        很简单明了,职员之间有上下级关系,每个职员有自己的happy值,越高在派对上就越能炒热气氛。但是必须是他的上司不在场的情况。求派对happy值的和最大能是多少。

题解

        题目中写的很明显:

It means that the supervisor relation forms a tree rooted at the rector V. E. Tretyakov. 

         所以肯定是有一个根的,可以把样例的图给画出来,比较好理解。那么我们对于每个职员都可以有2个状态,来或者不来。那么我们可以用01来表示i职员来或者不来。那么可以写出状态转移方程:

dp[上司][来] += dp[下属][不来];
dp[上司][不来] += Max(dp[下属][来],dp[下属][不来]);

因为我们是树形数据结构,那么对于上司,我们可以遍历他的下属,这样就解决了多下属的问题。但是我们必须从最垃圾的下属,就是叶子结点,自下向上到达根结点,那么就是树的递归操作了。

        大意如上,可以看代码自己在纸上画一遍流程,立马就能理解了。

AC代码 C++ 94ms

#include<iostream>
#include<vector>
#include<list>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<utility>
#include<queue>
#include<sstream>
#include<iterator>
#include<math.h>
#include<malloc.h>
#include<string.h>
#include<stack>
#define TIME std::ios::sync_with_stdio(false)
#define LL long long
#define MAX 6100
#define INF 0x3f3f3f3f

using namespace std;

int N;
int dp[MAX][2], father[MAX], step[MAX];

int Max(int a, int b) {
    return a > b ? a : b;
}

void init() {
    memset(dp, 0, sizeof(dp));
    memset(father, 0, sizeof(father));
    memset(step, 0, sizeof(step));
}

void dp_tree(int node) {
    step[node] = 1;
    for (int i = 1; i <= N; i++) {
        if (father[i] != node || step[i] == 1 ) continue;
        dp_tree(i);
        dp[node][1] += dp[i][0];
        dp[node][0] += Max(dp[i][0], dp[i][1]);
    }
}

int main() {
    TIME;
    while (scanf("%d",&N) != EOF) {
        init();
        for (int i = 1; i <= N; i++) {
            scanf("%d",&dp[i][1]);
        }
        int l, k;
        while (scanf("%d%d",&l,&k) != EOF) {
            if (l == 0 && k == 0) break;
            father[l] = k;
        }
        int root = 0;
        for (int i = 1; i <= N; i++) {
            if (father[i] != 0) continue;
            root = father[i];
            break;
        }
        dp_tree(root);
        int ans = Max(dp[root][0], dp[root][1]);
        printf("%d\n",ans);
    }

    system("pause");
    return 0;
}

总结

        首先,这个递归是有一点绕的,主要是这个数据结构的储存方式的原因。我们利用father数组,储存的职工A的上司,那么我们还想要从叶子结点先开始,那么就肯定要利用递归了,递归到叶子节点,再回溯回来。在无法确定叶子结点的情况下,这样是相对优解。但是这样也有一个问题:for循环遍历的太多了。写了一整个for循环就是为了找出N-1个结点中谁是下属。但用邻接矩阵仍然需要这样进行遍历。

         回溯的时候是dp的过程。所以树状dp其实没什么难的,就是在正常dp的情况下,利用树这个数据结构来进行操作而已。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值