中山市选2008 小树 题解

Description

给出一个树,树的边上有权值,现在要你求出一个满足下面三个要求的节点集合。
第一,根节点不在集合S中。
第二,集合中任何两个节点仅有一个公共祖先,即根节点。
第三,对集合中每个节点都要有两个值,wi表示到这个节点的路径上所有的边权值总和,di表示到这个节点的路径所包含的边数,现在要求sigma(wi)/sigma(di)的最大值。

Input

多组数据。
第一行一个数ca,表示有多少组测试数据。
对于每一组测试数据,第一行有一个整数N(1<=n<=1000),表示这棵树有多少个节点。
然后下面N-1行,每行有三个整树,x,y,z
(0<=x,y)
表示x,y之间有一条权值为z的边,编号为0的是根节点。

Output

对于每组测试数据,输出simga(wi)/sigma(di)的最大值,保留2位小数。

Sample Input

3
1
2
0 1 2
3
0 1 1
0 2 2

Sample Output

0.00
2.00
2.00

题解

先看题目,发现每棵以根节点的儿子的子树内只能选一个点或者不选。
观察答案的式子,发现当已知答案要合并另一个答案,只有两种情况:
1、原来两个答案相同,合并后不影响。
2、合并后的答案大于较小值,小于较大值。
因此得出结论:合并两个答案之后答案不上升。
因此最优情况一定是只选1个节点。
跑一遍bfs即可。

var tt,n,i,j,k,l,tot,x,y,z:longint;
dis,w,head,next,t,cc,q:array[0..100000]of longint;
p:array[0..100000]of boolean;
ans:real;
procedure ad(x,y,z:longint);
begin
  inc(tot);
  next[tot]:=head[x];
  head[x]:=tot;
  t[tot]:=y;
  cc[tot]:=z;
end;
procedure bfs;
var i,j,k:longint;
begin
  i:=0;
  k:=1;
  q[1]:=0;
  p[0]:=true;
  while i<k do begin
    inc(i);
    if (dis[q[i]]<>0)and(w[q[i]]/dis[q[i]]>ans) then ans:=w[q[i]]/dis[q[i]];
    j:=head[q[i]];
    while j<>0 do begin
      if p[t[j]] then begin
        j:=next[j];
        continue;
      end;
      inc(k);
      q[k]:=t[j];
      p[t[j]]:=true;
      w[t[j]]:=w[q[i]]+cc[j];
      dis[t[j]]:=dis[q[i]]+1;
      j:=next[j];
    end;
  end;
end;
begin
  readln(tt);
  while tt<>0 do begin
    dec(tt);
    readln(n);
    tot:=0;
    for i:=0 to n-1 do begin
      head[i]:=0;
      p[i]:=false;
    end;
    for i:=1 to n-1 do begin
      readln(x,y,z);
      ad(x,y,z);
      ad(y,x,z);
    end;
    ans:=0;
    bfs;
    writeln(ans:0:2);
  end;
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于洛谷上的p1036题目,我们可以使用Python来解决。下面是一个可能的解法: ```python def dfs(nums, target, selected_nums, index, k, sum): if k == 0 and sum == target: return 1 if index >= len(nums) or k <= 0 or sum > target: return 0 count = 0 for i in range(index, len(nums)): count += dfs(nums, target, selected_nums + [nums[i]], i + 1, k - 1, sum + nums[i]) return count if __name__ == "__main__": n, k = map(int, input().split()) nums = list(map(int, input().split())) target = int(input()) print(dfs(nums, target, [], 0, k, 0)) ``` 在这个解法中,我们使用了深度优先搜索(DFS)来找到满足要求的数列。通过递归的方式,我们遍历了所有可能的数字组合,并统计满足条件的个数。 首先,我们从给定的n和k分别表示数字个数和需要取的数字个数。然后,我们输入n个数字,并将它们存储在一个列表nums中。接下来,我们输入目标值target。 在dfs函数中,我们通过迭代index来择数字,并更新取的数字个数k和当前总和sum。如果k等于0且sum等于target,我们就找到了一个满足条件的组合,返回1。如果index超出了列表长度或者k小于等于0或者sum大于target,说明当前组合不满足要求,返回0。 在循环中,我们不断递归调用dfs函数,将取的数字添加到selected_nums中,并将index和k更新为下一轮递归所需的值。最终,我们返回所有满足条件的组合个数。 最后,我们在主程序中读入输入,并调用dfs函数,并输出结果。 这是一种可能的解法,但不一定是最优解。你可以根据题目要求和测试数据进行调试和优化。希望能对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值