POJ 2342&&HDU 1520解题报告

来源:互联网 发布:手机淘宝刷単平台软件 编辑:程序博客网 时间:2024/06/05 08:22

Anniversary party

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5596    Accepted Submission(s): 2571


Problem 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 T 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
711111111 32 36 47 44 53 50 0
 

Sample Output
5
 

Source
Ural State University Internal Contest October'2000 Students Session
 

Recommend
linle   |   We have carefully selected several similar problems for you:  1561 1011 2196 1494 2242 
            
       这道题是比较入门的树形dp题。状态也比较好想。题意是给你一棵树,树中父节点和子节点不能同时取,每个结点都有一个权值。求整个树的最大权值。
       因此对于每个结点而言就有选和不选两种状态。这和01背包有点像,但是不一样。如果选择了父节点,那么所有子节点都不能选。如果没选父节点,对于子节点而言可以选,也可以不选。我们选取这两种决策中的最大值即可。刚开始WA了几发,在输入数据上跪了。后来发现题目中说权值可以为负值。于是想起决策的那个过程是不是类似与最大子序列和。于是状态转移方程写成了下面的形式。最后也AC了。
       
void dfs(int u){    int len=G[u].size();    dp[u][1]=res[u];    rep(i,0,len)    {        int v=G[u][i];        dfs(v);    }    rep(i,0,len)    {        int v=G[u][i];        dp1[i+1]=max(dp1[i]+dp[v][0],dp[v][0]);  //dp1数组记录的是选了父节点的决策过程        dp2[i+1]=max(dp2[i]+max(dp[v][0],dp[v][1]),max(dp[v][0],dp[v][1]));//dp2数组记录的是不选父节点的决策过程    }    dp[u][0]+=dp2[len];    dp[u][1]+=dp1[len];}
     做完之后仔细想了想最大子序列的过程。那个是要求一个连续的段的序列值最大。而本题这么做应该是不对的。然后又仔细看了看,发现在dp2数组进行状态转移时对dp[v][0]和dp[v][1]取了max,这样的话,假设v是叶子结点,如果dp[v][1]为负数,那么dp[v][0]就是0,那么取完max后相当于整个序列都是非负数。这样按照最大子序列和的操作就没意义了。所以这样才AC了。实质上这样思考是不对的。
       继续考虑,在决策的时候贪心选择,只要是正数的dp[v][0]或者dp[v][1]的值都加上就行了。因而在进行最优决策的时候,有时候需要贪心选择最优的决策,有时候还需要再借助一次dp来确定最优决策。
       进行贪心决策以后,就可以这样写:
void dfs(int u){    int len=G[u].size();    dp[u][1]=res[u];    rep(i,0,len)    {        int v=G[u][i];        dfs(v);    }    int a=0,b=0;    rep(i,0,len)    {        int v=G[u][i];        int t=max(dp[v][0],dp[v][1]);        if(t>0) a+=t;        if(dp[v][0]>0) b+=dp[v][0];    }    dp[u][0]+=a;    dp[u][1]+=b;}
     当然也可以动态的在访问完每个结点v后就进行最优决策。
void dfs(int u){    int len=G[u].size();    dp[u][1]=res[u];    rep(i,0,len)    {        int v=G[u][i];        dfs(v);        dp[u][0]+=max(dp[v][0],dp[v][1]);  //这个取max很重要,有了这个max以后,就不用去考虑正负的问题。正负不会对状态转移产生影响        dp[u][1]+=dp[v][0];    }}
        在dp的时候除了要考虑状态转移之外,如何决策也是很重要的,在决策的时候要考虑全面,才能保证状态转移的正确性。状态转移是所有状态的转移,如果漏掉一些状态转移过程的话就有可能出错。
       参考代码:
#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<algorithm>#include<string>#include<vector>#include<map>#include<set>#include<stack>#include<queue>#include<ctime>#include<cstdlib>#include<iomanip>#include<utility>#define pb push_back#define mp make_pair#define CLR(x) memset(x,0,sizeof(x))#define _CLR(x) memset(x,-1,sizeof(x))#define REP(i,n) for(int i=0;i<n;i++)#define Debug(x) cout<<#x<<"="<<x<<" "<<endl#define REP(i,l,r) for(int i=l;i<=r;i++)#define rep(i,l,r) for(int i=l;i<r;i++)#define RREP(i,l,r) for(int i=l;i>=r;i--)#define rrep(i,l,r) for(int i=l;i>r;i--)#define read(x) scanf("%d",&x)#define put(x) printf("%d\n",x)#define ll long long#define lson l,m,rt<<1#define rson m+1,r,rt<<11using namespace std;int dp[6010][2],n,res[6010],in[6010];vector<int>G[6010];void dfs(int u){    int len=G[u].size();    dp[u][1]=res[u];    rep(i,0,len)    {        int v=G[u][i];        dfs(v);        dp[u][0]+=max(dp[v][0],dp[v][1]);        dp[u][1]+=dp[v][0];    }}int main(){    while(~read(n))    {        REP(i,1,n)        G[i].clear();        REP(i,1,n)        read(res[i]);        CLR(in);CLR(dp);        int u,v;        while(~scanf("%d%d",&u,&v)&&u+v)        {            G[v].pb(u);            in[u]++;        }        int rt=1;        for(; in[rt]; rt++);        dfs(rt);        printf("%d\n",max(dp[rt][0],dp[rt][1]));    }}

0 0
原创粉丝点击