transaction transaction transaction HDU - 6201(树上dp)

【题意】

 

给出一棵生成树,每个点有一个权值,代表商品的售价,树上每一条边上也有一个权值,代表从这条边经过所需要的花费。

 

现在需要你在树上选择两个点,一个作为买入商品的点,一个作为卖出商品的点,当然需要考虑从买入点到卖出点经过边的花费。使得收益最大。

 

允许买入点和卖出点重合,即收益最小值为0.

 

【思路】

 我的方法:从根到当前节点记录最少成本,再从叶子节点到当前节点记录最少的成本和最高的收入,得出该点在该子树上的最高利润。

#include <cstdio>
#include <iostream>
#include <cstring>

using namespace std;

const int maxn=1e5+10;

int buy[maxn],sale[maxn];
int head[maxn<<1],id[maxn<<1],nt[maxn<<1],wt[maxn<<1],cnt;
int n,p[maxn];
void init()
{
    memset(head,-1,sizeof(head));
    cnt=0;
}
void add(int x,int y,int w)
{
    id[cnt]=y;
    nt[cnt]=head[x];
    wt[cnt]=w;
    head[x]=cnt++;
}

int dfs(int u,int pre,int b)
{
    buy[u]=sale[u]=p[u];
    int ret=p[u]-b;
    for(int i=head[u];i!=-1;i=nt[i])
    {
        int v=id[i],w=wt[i];
        if(v==pre) continue;
        ret=max(ret,dfs(v,u,min(b+w,p[u]+w)));

        buy[u]=min(buy[v]+w,buy[u]);
        sale[u]=max(sale[v]-w,sale[u]);
    }

    return max(ret,(sale[u]-buy[u]));
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        init();
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
            scanf("%d",p+i);

        for(int i=1;i<n;i++)
        {
            int x,y,w;
            scanf("%d%d%d",&x,&y,&w);
            add(x,y,w);
            add(y,x,w);
        }
        int ans=dfs(1,0,10001);
        cout<<ans<<endl;
    }

}
View Code

大佬方法:

我们设1为根节点,假设一开始一个人身上的钱为0。

 

我们设dp[i][0]表示从i及其子树并中任一点买入一本书并走到i点后这个人身上钱的最大值(显然是负的)。

 

dp[i][1]表示从i及其子树并中任一点卖出一本书并走到i点后这个人身上钱的最大值(可正可负)。

 

那么我们对这棵树进行一次树形DP即可,dfs后对每个节点更新收益最大值,单点的计算方法为

 

w=dp[i][0]+dp[i][1]

 

(由于前者是负的,相当于收入减去总花费)

 

对比我的方法,直接从叶子节点收束就行了,已经包含了靠近根节点的买,远离的卖的情况,不需要再从根节点往下传参数了。

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)
 
typedef long long ll;
const int maxn = 100005;
const ll mod = 1e9+7;
const int INF = 0x3f3f3f3f;
const double eps = 1e-6;
 
struct node
{
    int v,w;
    node(int _v,int _w):v(_v),w(_w) {}
};
 
int n,ans;
int val[maxn];
int dp[maxn][2];
vector<node>vec[maxn];
 
void dfs(int u,int pre)
{
    dp[u][0]=-val[u];
    dp[u][1]=val[u];
    for(int i=0;i<vec[u].size();i++)
    {
        int v=vec[u][i].v;
        int w=vec[u][i].w;
        if(v==pre) continue;
        dfs(v,u);
        dp[u][0]=max(dp[u][0],dp[v][0]-w);
        dp[u][1]=max(dp[u][1],dp[v][1]-w);
    }
    ans=max(ans,dp[u][0]+dp[u][1]);
}
 
int main()
{
    int u,v,w;
    rush()
    {
        scanf("%d",&n);
        for(int i=0;i<=n;i++)
        {
            vec[i].clear();
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&val[i]);
        }
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            vec[u].push_back(node(v,w));
            vec[v].push_back(node(u,w));
        }
        ans=0;
        dfs(1,-1);
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2020-03-08 20:12  Npunchman  阅读(110)  评论(0)    收藏  举报