您的位置:首页 > 运维架构

Topcoder SRM666 DIV2第三题,树形DP

2015-08-26 21:32 351 查看
题意:

给一个具有n个节点的树,每个节点上有一个值v,现在从节点1开始,走L步,问L步中经过的v值之和最大为多少。若一个点被重复走过,这个权值只计算一次。

范围:

1<n<=50,0<=L<=100,0<=v<=100。

树形DP解决,状态分析:

dp[u][1][step]:表示从节点u开始,走step步,此时回到u点,经过的点的最大权值之和。

dp[u][0][step]:表示从节点u开始,走step步,此时没有回到u点,经过的点的最大权值之和。

状态转移:

走step步回到u点,只有一种转移方法:child表示当前的子树,我们都从当前子树考虑,若能转移,当前子树也必须回到child点。所以转移方程为:

dp[u][1][step]=max(dp[u][1][step],dp[u][1][i]+dp[child][1][step-i-2]):dp[u][1][i]从前面的几个孩子求得的值,dp[child][1][step-i-2]当前孩子必须回到child点,-2表示u->child的边,来回的步数。

走step步没有回到u点,有两种转移方法:也是从当前子树考虑。若能转移,可以有两种情况:

①当前子树回到child点,前面考虑的子树没有回到u点;

dp[u][0][step]=max(dp[u][0][step],dp[u][0][i]+dp[child][1][step-i-2])

②当前子树没回到child点,前面考虑的子树回到了u点。

dp[u][0][step]=max(dp[u][0][step],dp[u][1][i]+dp[child][0][step-i-1])

大体思路如上,具体实现细节需要注意一下边界情况,还有在用一棵子树转移的时候,为了防止这棵子树跟自己本身的转移,导致有些点被重复采集,这里采用了tmp[][][]数组存储了当前子树更新了的一些状态,防止这些更新的状态被本棵树再次利用,这里主要是这目的,然后在对这棵树转移结束后,在用tmp数组更新dp数组。如下:

tmp[u][1][i]=max(tmp[u][1][i],dp[u][1][j]+dp[child][1][i-j-2]);
tmp[u][0][i]=max(tmp[u][0][i],dp[u][1][j]+dp[child][0][i-j-1]);
<pre name="code" class="html">tmp[u][0][i]=max(tmp[u][0][i],dp[u][0][j]+dp[child][1][i-j-2]);




具体代码实现如下:

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>

using namespace std;
#define N 55
class CollectingTokens {
public:
	int maxTokens(vector <int>, vector <int>, vector <int>, int);
	vector<int> edge
;
	int val
;
	int st;
	int dp
[2][105];
	int tmp
[2][105];
    void dfs(int u,int v);
    void cal(int u,int child);
    void Copy(int u);
};
void CollectingTokens::Copy(int u)
{
    for(int i=0;i<=st;i++)
    {
        for(int j=0;j<=i;j++)
        {
            if((i-j-2>=0)&&(i%2==0)&&(j%2==0))
                dp[u][1][i]=tmp[u][1][i];
            if(i-j-1>=0)
                dp[u][0][i]=tmp[u][0][i];
            if(i-j-2>=0)
                dp[u][0][i]=tmp[u][0][i];
        }
    }
}
void CollectingTokens::cal(int u,int child)
{
    for(int i=0;i<=st;i++)
    {
        tmp[u][1][i]=dp[u][1][i];
        tmp[u][0][i]=dp[u][0][i];
        for(int j=0;j<=i;j++)
        {
            if((i-j-2>=0)&&(i%2==0)&&(j%2==0))
            tmp[u][1][i]=max(tmp[u][1][i],dp[u][1][j]+dp[child][1][i-j-2]);
            if(i-j-1>=0)
            tmp[u][0][i]=max(tmp[u][0][i],dp[u][1][j]+dp[child][0][i-j-1]);
            if(i-j-2>=0)
            tmp[u][0][i]=max(tmp[u][0][i],dp[u][0][j]+dp[child][1][i-j-2]);
        }
    }
    Copy(u);
}
void CollectingTokens::dfs(int u,int pr)
{
    int len=edge[u].size();
    int num=0,child;
    dp[u][1][0]=dp[u][0][0]=val[u];
    for(int i=0;i<len;i++)
    {
        child=edge[u][i];
        if(child==pr) continue;
        num++;
        dfs(child,u);
        cal(u,child);
    }
    if(num==0)
    {
        for(int i=0;i<=st;i++)
        {
            dp[u][1][i]=val[u];
            dp[u][0][i]=val[u];
        }
    }
}
int CollectingTokens::maxTokens(vector <int> A, vector <int> B, vector <int> tokens, int L) {
	int len=A.size();
	for(int i=0;i<len;i++)
    {
        edge[A[i]].push_back(B[i]);
        edge[B[i]].push_back(A[i]);
	}
    for(int i=0;i<len+1;i++)
        val[i+1]=tokens[i];
    st=L;
    memset(dp,0,sizeof(dp));
    dfs(1,1);
    int ans=0;
    for(int i=0;i<=st;i++)
        ans=max(ans,max(dp[1][1][i],dp[1][0][i]));
    return ans;
}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: