hdu 2196 computer(树形dp)

大家可以看看这个博客:http://blog.csdn.net/woshi250hua/article/details/7642536
题目较难。
题目大意:给一棵树,每条树边都有权值,问从每个顶点出发,经过的路径权值之和最大为多少?每条树边都只能走一次,n <= 10000,权值<=10^9
如何
思路:比较复杂的树形DP,刚看到题目一点思路都没有,但一想金华赛区的那道B题,似乎有点相似,那题是先深搜一次看每个节点拥有多少子孙节点和子孙节点的权值和。这题要记录的信息比较多,状态转移也比较复杂。设定1为树根(其实每个节点当根都是一样的),这样树变成了有向树,每个节点都有若干个子分支,用一次深搜从叶子节点往上更新算出每个分支到叶子节点的最大权值和。此时得出了根节点到其他分支的最大权值和。得出上面的信息之后,怎么得到答案呢?其他节点的计算类似于根节点。从根节点的孩子出发,先找到根节点除当前分支(根->当前节点为一个分支)外其他分支的最大权值和,然后往上更新选择的这条分支权值和,也就是父亲节点找到的其他分支最大权值和+树边的权值,见Tree_DP()的第二个While循环。不断递归重复上述过程即可得解。
- 如何构造图?
定义 一个结构体

struct node
{
    int v,len,sum;
    node* next;
}*head[MAX*2],tree[MAX*2];

对于所有连接同一个节点的节点,用next串起来。
head[v]指向连向节点v编号靠后的节点,最终该链指向节点v。

#include<iostream>
#include<cstdio>
using namespace std;
#define max(a,b) (a)>(b)?(a):(b);
const int maxn=10005;
struct node
{
    int v,len,sum;
    node* next;
}*head[2*maxn],tree[2*maxn];
int ptr,n;
int vis[maxn],dp[maxn];
void init()
{
    ptr=1;
    memset(vis,0,sizeof(vis));
    memset(dp,0,sizeof(dp));
    memset(head,NULL,sizeof(head));
}
void AddEdge(int x,int y,int len)
{
    tree[ptr].v = y;
    tree[ptr].len = len;  
    tree[ptr].next = head[x];
    head[x] = &tree[ptr++];  
    tree[ptr].v = x;
    tree[ptr].len = len;  
    tree[ptr].next = head[y];
    head[y] = &tree[ptr++];  
}
void dfs(int v)
{
    vis[v]=1;
    node *p=head[v];
    while(p!=NULL)
    {
        if(!vis[p->v])
        {
            dfs(p->v);
            dp[v]=max(dp[v],dp[p->v]+p->len);
            p->sum=dp[p->v]+p->len;
        }
        p=p->next;
    }
}
void Tree_dp(int v,int son)
{
    if(vis[son]==1) return ;
    vis[son]=1;
    int maxx=0;
    node* p=head[v];
    while(p!=NULL)
    {
        if(p->v!=son)
        {
            maxx=max(maxx,p->sum);
        }
        p=p->next;
    }
    p=head[son];
    while(p!=NULL)
    {
        if(p->v==v)
        {
            p->sum=maxx+p->len;
            break;
        }
        p=p->next;
    }
    p=head[son];
    while(p!=NULL)
    {
        dp[son] = max(dp[son],p->sum);
        Tree_dp(son,p->v);
        p=p->next;
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        int a,b;
        init();
        for(int i=2;i<=n;i++)
        {
            scanf("%d%d",&a,&b);
            AddEdge(i,a,b);
        }
        dfs(1);
        memset(vis,0,sizeof(vis));
        node *p=head[1];
        while(p!=NULL)
        {
            Tree_dp(1,p->v);
            p=p->next;
        }
        for(int i=1;i<=n;i++)
            printf("%d\n",dp[i]);
    }
    return 0;
}

你可能感兴趣的:(dp)