[枚举]Luogu P1268 树的重量

题目描述

树可以用来表示物种之间的进化关系。一棵“进化树”是一个带边权的树,其叶节点表示一个物种,两个叶节点之间的距离表示两个物种的差异。现在,一个重要的问题是,根据物种之间的距离,重构相应的“进化树”。

令N={1..n},用一个N上的矩阵M来定义树T。其中,矩阵M满足:对于任意的i,j,k,有M[i,j] + M[j,k] >= M[i,k]。树T满足:

1.叶节点属于集合N;

2.边权均为非负整数;

3.dT(i,j)=M[i,j],其中dT(i,j)表示树上i到j的最短路径长度。

如下图,矩阵M描述了一棵树。

树的重量是指树上所有边权之和。对于任意给出的合法矩阵M,它所能表示树的重量是惟一确定的,不可能找到两棵不同重量的树,它们都符合矩阵M。你的任务就是,根据给出的矩阵M,计算M所表示树的重量。下图是上面给出的矩阵M所能表示的一棵树,这棵树的总重量为15。

输入输出格式

输入格式:

输入数据包含若干组数据。每组数据的第一行是一个整数n(2<n<30)。其后n-l行,给出的是矩阵M的一个上三角(不包含对角线),矩阵中所有元素是不超过100的非负整数。输入数据保证合法。

输入数据以n=0结尾。

输出格式:

对于每组输入,输出一行,一个整数,表示树的重量。

输入输出样例

输入样例#1: 复制

5
5 9 12 8
8 11 7
5 1
4
4
15 36 60
31 55
36
0

输出样例#1: 复制

15
71

题解

  • 盗用一张图先
  • 这张图的树的重量为(1,2)+蓝色部分
  • 那么蓝色部分怎么求?
  • 发现,(1,3)和(2,3)都是经过蓝色部分的
  • 把它们相加发现:(1,2)+2*蓝色部分
  • 而且已知(1,2),蓝色部分就用容易求
  • 用字母表示就是:((1,i)+(j,i)-(1,j))/2
  • 解决这个问题后,考虑怎么构造树
  • 这棵树要满足:
  • ①符合矩阵  ②每条边都要加一次,而且最多一次
  • 假如我们前i-1个都构造完了,那么怎么构造i个
  • 题目要求重量要尽量小,显然就枚举加入哪条边中,取最小值
  • Ojbk!!

代码

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 const int inf=(1<<30);
 5 int d[60][60],n;
 6 int main()
 7 {
 8     while(scanf("%d",&n)==1&&n)
 9     {
10         for(int i=1;i<=n;i++)
11             for(int j=i+1;j<=n;j++)
12                  scanf("%d",&d[i][j]),d[j][i]=d[i][j];
13         int ans=d[1][2];
14         for(int i=3;i<=n;i++)
15         {
16             int t=inf;
17             for(int j=2;j<i;j++) t=min(t,(d[1][i]+d[j][i]-d[1][j])/2);
18             ans+=t;
19         }
20         printf("%d\n",ans);
21     }
22     return 0;
23 }

原文地址:https://www.cnblogs.com/Comfortable/p/8585089.html

时间: 2024-11-10 14:07:45

[枚举]Luogu P1268 树的重量的相关文章

P1268 树的重量

题目描述 树可以用来表示物种之间的进化关系.一棵“进化树”是一个带边权的树,其叶节点表示一个物种,两个叶节点之间的距离表示两个物种的差异.现在,一个重要的问题是,根据物种之间的距离,重构相应的“进化树”. 令N={1..n},用一个N上的矩阵M来定义树T.其中,矩阵M满足:对于任意的i,j,k,有M[i,j] + M[j,k] >= M[i,k].树T满足: 1.叶节点属于集合N: 2.边权均为非负整数: 3.dT(i,j)=M[i,j],其中dT(i,j)表示树上i到j的最短路径长度. 如下图

P1268 树的重量【构造】

题目描述 树可以用来表示物种之间的进化关系.一棵“进化树”是一个带边权的树,其叶节点表示一个物种,两个叶节点之间的距离表示两个物种的差异.现在,一个重要的问题是,根据物种之间的距离,重构相应的“进化树”. 令N={1..n},用一个N上的矩阵M来定义树T.其中,矩阵M满足:对于任意的i,j,k,有M[i,j] + M[j,k] >= M[i,k].树T满足: 1.叶节点属于集合N: 2.边权均为非负整数: 3.dT(i,j)=M[i,j],其中dT(i,j)表示树上i到j的最短路径长度. 如下图

p1268树的重量 题解

题面描述点此qwq. 正解开始. 一道茅塞顿开恍然大悟的题目: 第一眼看到这个题的时候,语文不好的我对着题目中的 这些,和: 这句话发呆半天,,,, 因为不关我怎么构建几何模型,我都不理解这句话.. (吐槽题面臃肿!) 然后想了一下,发现题目是这个亚子: 给你一个矩阵M,M上每一个节点(i,j)表示叶子结点i和叶子结点j的距离,每个矩阵有且只能生成唯一一个树(不然这题没法搞了),让你求这棵树上的每一条边的权值和. 在李姐(lz dalao)完题目之后,我又开始懵了......到底怎么搞非叶节点的

LG1268树的重量

#include<bits/stdc++.h> using namespace std; #define N 35 #define INF 1e9 int dis[N][N],n,len,ans; int main(){ while(scanf("%d",&n)){ if(!n) break; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) scanf("%d",&dis[i][j]

Get Many Persimmon Trees_枚举&amp;&amp;二维树状数组

Description Seiji Hayashi had been a professor of the Nisshinkan Samurai School in the domain of Aizu for a long time in the 18th century. In order to reward him for his meritorious career in education, Katanobu Matsudaira, the lord of the domain of

cogs luogu 砍树

★   输入文件:eko.in   输出文件:eko.out   简单对比 时间限制:1 s   内存限制:256 MB [题目描述] N棵树,每棵都有一个整数高度.有一个木头的总需要量M. 现在确定一个最大的统一的砍树高度H,如果某棵树的高度大于H,则高出的部分被砍下.使得所有被砍下的木材长度之和达到M(允许稍超过M). 例如,有4棵树,高度分别是20 15 10 17, 需要的木材长度为 7,砍树高度为15时,第1棵树被砍下5,第4棵树被砍下2,得到的总长度为7.如果砍树高度为16时,第1棵

Luogu P2590 树的统计(树链剖分+线段树)

题意 原文很清楚了 题解 重链剖分模板题,用线段树维护即可. #include <cstdio> #include <cstring> #include <algorithm> using std::max; using std::swap; const int N = 3e4 + 10, Inf = 1e9 + 7; int n, q, c[N], x, y; int fa[N], dep[N], son[N], siz[N]; int top[N], w[N], d

swift_枚举 | 可为空类型 | 枚举关联值 | 枚举递归 | 树的概念

***************可为空的类型 var demo2 :we_demo = nil 上面这个代码串的语法是错的 为什么呢, 在Swift中,所有的类型定义出来的属性的默认值都不可以是nil 不管是普通简单值类型还是引用类型 那我就是要让这个属性默认值为空,为nil 怎么办呢,很简单,用语法,在定义这个属性的时,在类型后面声明一个? 这样就表示这个属性除了指定类型的默认值外还可以是一个可为空的类型 在Java中,最常见的错误类型就是NullPoinExecption, 为什么就是要有Nu

初学树型dp

树型DP DFS的回溯是树形DP的重点以及核心,当回溯结束后,root的子树已经被遍历完并处理完了.这便是树形DP的最重要的特点 自己认为应该注意的点 好多人都说在更新当前节点时,它的儿子结点都给更新完了,实际上这并不准确.对于当前节点,我们需要dfs它的儿子,并且在dfs中进行dp.在此过程中并不是等到儿子都更新完我们才更新当前节点的信息(假设当前节点为x, 有儿子son1 , son2, son3, 且son1已经更新完了, 即x已有了son1的信息, son2刚刚更新完,即dfs正在son