hdu4118 树形dp

http://acm.hdu.edu.cn/showproblem.php?pid=4118

Problem Description

Nowadays, people have many ways to save money on accommodation when they are on vacation.

One of these ways is exchanging houses with other people.

Here is a group of N people who want to travel around the world. They live in different cities, so they can travel to some other people‘s city and use someone‘s house temporary. Now they want to make a plan that choose a destination for each person. There are
2 rules should be satisfied:

1. All the people should go to one of the other people‘s city.

2. Two of them never go to the same city, because they are not willing to share a house.

They want to maximize the sum of all people‘s travel distance. The travel distance of a person is the distance between the city he lives in and the city he travels to. These N cities have N - 1 highways connecting them. The travelers always choose the shortest
path when traveling.

Given the highways‘ information, it is your job to find the best plan, that maximum the total travel distance of all people.

Input

The first line of input contains one integer T(1 <= T <= 10), indicating the number of test cases.

Each test case contains several lines.

The first line contains an integer N(2 <= N <= 105), representing the number of cities.

Then the followingN-1 lines each contains three integersX, Y,Z(1 <= X, Y <= N, 1 <= Z <= 106), means that there is a highway between city X and city Y , and length of that highway.

You can assume all the cities are connected and the highways are bi-directional.

Output

For each test case in the input, print one line: "Case #X: Y", where X is the test case number (starting with 1) and Y represents the largest total travel distance of all people.

Sample Input

2
4
1 2 3
2 3 2
4 3 2
6
1 2 3
2 3 4
2 4 1
4 5 8
5 6 5

Sample Output

Case #1: 18
Case #2: 62
/**
hdu 4118 树形dp
题目大意:一棵n节点的树,每个节点有一个人,每个人离开自己的位置到另一个位置,每个位置只能有一个人,问这n个人移动距离和的最大值。
解题思路:(转)如果找出树的重心就可以把树分成左右两部分,左边的点跟右边的点交换位置,两点交换位置的距离=两点到根节点的距离之和的2倍,
           总距离就是所有点到根节点距离之和的2倍了,当时犹豫了一下,如果节点数是奇数的话,这样是不是根节点没换位置呢?后来一想,
           这种交换位置每个点走的路径都经过根节点,根节点跟任意一个点交换一下就可以了,答案还是一样的。
           树形DP:我们可以统计没条边被走了多少次,一条边可以把点分为左右两部分,两部分中点数较少的一部分都要离开自己的位置去另一边,
           这条边被走了min(son[u](右边点数),son[v])*2次,点数多的一部分有的位置是没变的,但是我们这样把每条边都操作一遍后,所有点的位置都变了。
注:递归dfs会爆内存。
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long LL;
const int maxn=100005;

struct note
{
    int v,w,next;
} edge[maxn*2];

int head[maxn],ip;
int n,vis[maxn],num[maxn],sta[maxn];
LL ans;

void init()
{
    memset(head,-1,sizeof(head));
    ip=0;
}

void addedge(int u,int v,int w)
{
    edge[ip].v=v,edge[ip].w=w,edge[ip].next=head[u],head[u]=ip++;
}

///递归形式会超出内存
void dfs(int u,int pre)
{
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==pre)continue;
        dfs(v,u);
        num[u]+=num[v];
        ans+=(LL)edge[i].w*2*min(num[v],n-num[v]);
    }
    num[u]++;
}

///用栈实现非递归形式
void dfs1(int u)
{
    memset(vis,0,sizeof(vis));
    int top=0;
    sta[top++]=u;
    vis[u]=1;
    while(top>0)
    {
        bool flag=1;
        int t=sta[top-1];
        for(int i=head[t]; i!=-1; i=edge[i].next)
        {
            int v=edge[i].v;
            if(vis[v])continue;
            sta[top++]=v;
            vis[v]=1;
            flag=0;
        }
        if(flag==0)continue;
        for(int i=head[t]; i!=-1; i=edge[i].next)
        {
            int v=edge[i].v;
            if(num[v]!=0)
            {
                num[t]+=num[v];
                ans+=(LL)edge[i].w*2*min(num[v],n-num[v]);
            }
        }
        num[t]++;
        top--;
    }
}

int main()
{
    int T,tt=0;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        init();
        for(int i=1; i<n; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        }
        ans=0;
        memset(num,0,sizeof(num));
        ///dfs1(1);
        dfs(1,-1);
        printf("Case #%d: %I64d\n",++tt,ans);
    }
    return 0;
}
时间: 2024-10-11 20:31:13

hdu4118 树形dp的相关文章

hdu-4118 Holiday&#39;s Accommodation(树形dp+树的重心)

题目链接: Holiday's Accommodation Time Limit: 8000/4000 MS (Java/Others)     Memory Limit: 200000/200000 K (Java/Others) Problem Description Nowadays, people have many ways to save money on accommodation when they are on vacation.One of these ways is exc

HDU-2196 Computer (树形DP)

最近在看树形DP,这题应该是树形DP的经典题了,写完以后还是有点感觉的.之后看了discuss可以用树分治来做,以后再试一试. 题目大意 找到带权树上离每个点的最远点.︿( ̄︶ ̄)︿ 题解: 对于每一个点的最远点,就是以这个点为根到所有叶子节点的最长距离.但是如果确定根的话,除了根节点外,只能找到每个节点(度数-1)个子树的最大值,剩下一个子树是该节点当前的父亲节点. 所以当前节点的最远点在当前节点子树的所有叶子节点以及父亲节点的最远点上(当父亲节点的最远点不在当前节点的子树上时), 如果父亲节

UVA-01220 Party at Hali-Bula (树形DP+map)

题目链接:https://vjudge.net/problem/UVA-1220 思路: 树形DP模板题,求最大人数很简单,难点在于如何判断最大人数的名单是否有不同的情况: 解决方法是用一个数组f[manx][2]记录该节点是否出场的情况,为真时代表有多种情况; 具体讨论: 当父节点的值加上某个子节点的值时,他的f的情况也和该子节点一样: 当某个节点dp(i, 0) == dp(i, 1), 则该节点以及它的父节点也一定有多种情况(父节点必定取其中之一). Code: 1 #include<bi

HDU 1520 树形dp裸题

1.HDU 1520  Anniversary party 2.总结:第一道树形dp,有点纠结 题意:公司聚会,员工与直接上司不能同时来,求最大权值和 #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #define max(a,b) a>b?a:b using nam

HDU2196 Computer(树形DP)

和LightOJ1257一样,之前我用了树分治写了.其实原来这题是道经典的树形DP,感觉这个DP不简单.. dp[0][u]表示以u为根的子树中的结点与u的最远距离 dp[1][u]表示以u为根的子树中的结点与u的次远距离 这两个可以一遍dfs通过儿子结点转移得到.显然dp[0][u]就是u的一个可能的答案,即u往下走的最远距离,还缺一部分就是u往上走的最远距离: dp[2][u]表示u往上走的最远距离 对于这个的转移,分两种情况,是这样的: dp[2][v] = max( dp[0][u]+w

hdu5593--ZYB&#39;s Tree(树形dp)

问题描述 ZYB有一颗N个节点的树,现在他希望你对于每一个点,求出离每个点距离不超过KK的点的个数. 两个点(x,y)在树上的距离定义为两个点树上最短路径经过的边数, 为了节约读入和输出的时间,我们采用如下方式进行读入输出: 读入:读入两个数A,B,令fai??为节点i的父亲,fa?1??=0;fa?i??=(A∗i+B)%(i−1)+1,i∈[2,N] . 输出:输出时只需输出N个点的答案的xor和即可. 输入描述 第一行一个整数TT表示数据组数. 接下来每组数据: 一行四个正整数N,K,A,

CF 219D Choosing Capital for Treeland 树形DP 好题

一个国家,有n座城市,编号为1~n,有n-1条有向边 如果不考虑边的有向性,这n个城市刚好构成一棵树 现在国王要在这n个城市中选择一个作为首都 要求:从首都可以到达这个国家的任何一个城市(边是有向的) 所以一个城市作为首都,可能会有若干边需要改变方向 现在问,选择哪些城市作为首都,需要改变方向的边最少. 输出最少需要改变方向的边数 输出可以作为首都的编号 树形DP 先假定城市1作为首都 令tree(i)表示以i为根的子树 dp[i]表示在tree(i)中,若以i为首都的话,需要改变的边数 第一次

HDU 1011 Starship Troopers(树形dp+背包)

Starship Troopers Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 13109    Accepted Submission(s): 3562 Problem Description You, the leader of Starship Troopers, are sent to destroy a base of

Codeforces 462D Appleman and Tree 树形dp

题目链接:点击打开链接 题意: 给定n个点的树, 0为根,下面n-1行表示每个点的父节点 最后一行n个数 表示每个点的颜色,0为白色,1为黑色. 把树分成若干个联通块使得每个联通块有且仅有一个黑点,问有多少种分法(结果mod1e9+7) 思路: 树形dp,每个点有2个状态,已经归属于某个黑点和未归属于某个黑点. #include <cstdio> #include <vector> #include <iostream> using namespace std; #de