boj 1204 让树的根结点到叶子结点等长的问题

地址:http://acm.scs.bupt.cn/onlinejudge/showproblem.php?problem_id=1204

EqualTree Submit: 105    Accepted:29 Time Limit: 1000MS  Memory Limit: 65536K

Description
给定一棵有根树,每条边上都有一个正的长度,现在你可以延长某些边的长度,使得所有的叶子结点到根的距离相等,并且延长的长度最小。



Input
多组测试数据,以两个0结束。

第一行为两个整数N,R。N表示结点的个数(编号为0到N-1),R表示树的根。

接下来N-1行,每行三个整数a b c,表示a、b结点之间边的长度为c。

2<= N <= 1000,1<= c <= 1000


Output
对于每组测试数据,输出一行,为需要延长的最小值。


Sample Input

4 0
0 1 1
0 3 3
0 2 2
2 0
0 1 100
0 0


Sample Output

3
0

 

 

思路:从根结点开始,遍历树,用递归,根结点的每个子树分别遍历

//#include<stdio.h>
#include<iostream>
//#include<string.h>

//using namespace std;
#define MAXN 1010
int n,root;
int count[1010];
struct
{
  int length;
  int target;    
       }a[MAXN][MAXN];       //距离 以及指向目标
bool used[MAXN];             
int DFS(int currentnode,int &maxdeep)
{
    used[currentnode]=true;           //因为两个节点是相互指向的,将当前节点制为true,可以防止下个节点返回当前节点
    int cost=0;
    int total=0;                    //已经遍历的节点个数
    maxdeep=0;                     //最大深度
    for(int i=0;i<count[currentnode];i++)         //开始遍历
    {
       int target=a[currentnode][i].target;        //当前结点指向的下一个结点
        if(!used[target])                          //该条件使得当前结点不会返回已经遍历过得结点
        {
          int deep=0;                               //深度
          cost+=DFS(target,deep);                     //递归进去 把子树的距离算出来
          deep+=a[currentnode][i].length;           //子树距离加上根结点到当前结点距离
          if(deep>maxdeep)                          //比较 如果当前距离大于最大距离
          {
             cost+=(deep-maxdeep)*total;             //所有其他(total)个结点都拉长deep-maxdeep个
              maxdeep=deep;            
                          }
           else
             cost+=maxdeep-deep;                  //否则只自己拉长
            
            total++;                               //遍历结点数+1
                         }
            
            }
   
      return cost;
    }
int main()
{
    while(scanf("%d%d",&n,&root)!=EOF)
    {
          memset(count, 0, sizeof count);
        memset(used, 0, sizeof used);

         if(n==root&&n==0)
         break;
         else
         {
             for(int i=0;i<n-1;i++)
             {
               int d,b,c;
             scanf("%d%d%d",&d,&b,&c);
              a[d][count[d]].length=c;          //建立边。count[]数组记录的是有几个边。建立边时候两点互相建立
              a[d][count[d]].target=b;
              a[b][count[b]].length=c;
              a[b][count[b]].target=d;
              count[d]++;
              count[b]++;
             }
             int maxdeep=0;
             printf("%d/n",DFS(root,maxdeep));
            
             }                            
                                      }
                         //  system("pause");
    return 0;
   
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值