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-1行,给出的是矩阵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

和Three Paths on a tree类似地构造一个树上最短路的式子把整张图看作一张AOE网
通过这张网来建立一棵树,具体实现操作是:1、把一个为入树的点入树2、在已经入树的它的邻接点中遍历来更新把这个点入树的最小花费。

显然此时花费是 (dis[i][k] + dis[j][k] - dis[i][j]) / 2;

3、树的总重量加上把这个点入树的最小花费

CODE

 1 #include <bits/stdc++.h>
 2 #define dbg(x) cout << #x << "=" << x << endl
 3 #define eps 1e-8
 4 #define pi acos(-1.0)
 5
 6 using namespace std;
 7 typedef long long LL;
 8
 9 template<class T>inline void read(T &res)
10 {
11     char c;T flag=1;
12     while((c=getchar())<‘0‘||c>‘9‘)if(c==‘-‘)flag=-1;res=c-‘0‘;
13     while((c=getchar())>=‘0‘&&c<=‘9‘)res=res*10+c-‘0‘;res*=flag;
14 }
15
16 namespace _buff {
17     const size_t BUFF = 1 << 19;
18     char ibuf[BUFF], *ib = ibuf, *ie = ibuf;
19     char getc() {
20         if (ib == ie) {
21             ib = ibuf;
22             ie = ibuf + fread(ibuf, 1, BUFF, stdin);
23         }
24         return ib == ie ? -1 : *ib++;
25     }
26 }
27
28 int qread() {
29     using namespace _buff;
30     int ret = 0;
31     bool pos = true;
32     char c = getc();
33     for (; (c < ‘0‘ || c > ‘9‘) && c != ‘-‘; c = getc()) {
34         assert(~c);
35     }
36     if (c == ‘-‘) {
37         pos = false;
38         c = getc();
39     }
40     for (; c >= ‘0‘ && c <= ‘9‘; c = getc()) {
41         ret = (ret << 3) + (ret << 1) + (c ^ 48);
42     }
43     return pos ? ret : -ret;
44 }
45
46 const int maxn = 107;
47
48 int dis[maxn][maxn];
49 int n;
50
51 int main()
52 {
53     while(scanf("%d",&n) && n) {
54         memset(dis, 0, sizeof(dis));
55         for ( int i = 1; i <= n; ++i ) {
56             for ( int j = i+1; j <= n; ++j ) {
57                 read(dis[i][j]);
58                 dis[j][i] = dis[i][j];
59             }
60         }
61         int weight = 0;
62         int v = 1;
63         for ( int i = 1; i <= n; ++i ) {
64             int cost = 0x3f3f3f3f;
65             for ( int j = 1; j < i; ++j ) {
66                 int temp = dis[i][v] + dis[i][j] - dis[v][j];
67                 cost = min(cost, temp / 2);
68                 //dbg(cost);
69             }
70             if(cost != 0x3f3f3f3f)
71                 weight += cost;
72         }
73         cout << weight << endl;
74     }
75     return 0;
76 }




原文地址:https://www.cnblogs.com/orangeko/p/12336209.html

时间: 2024-08-30 07:56:57

P1268 树的重量【构造】的相关文章

[枚举]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的最短路径长度. 如下图

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)完题目之后,我又开始懵了......到底怎么搞非叶节点的

二叉树排序树的的构造和查找

/********************************************************* 二叉树排序树的的构造和查找 *********************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <stack&g

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]

Aizu 1263 Network Mess 树的直径+构造

题目链接:点击打开链接 Network Mess Gilbert is the network admin of Ginkgo company. His boss is mad about the messy network cables on the floor. He finally walked up to Gilbert and asked the lazy network admin to illustrate how computers and switches are connec

哈夫曼树原理及构造(转载)

构造哈夫曼树的过程是这样的 一.构成初始集合 对给定的n个权值{W1,W2,W3,...,Wi,...,Wn}构成n棵二叉树的初始集合F={T1,T2,T3,...,Ti,...,Tn},其中每棵二叉树Ti中只有一个权值为Wi的根结点,它的左右子树均为空.(为方便在计算机上实现算法,一般还要求以Ti的权值Wi的升序排列.) 二.选取左右子树 在F中选取两棵根结点权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树的根结点的权值之和. 三.删除左右子树 从F中删除这两棵树,

BZOJ5203 [NEERC2017 Northern] Grand Test 【dfs树】【构造】

题目分析: 首先观察可知这是一个无向图,那么我们构建出它的dfs树.由于无向图的性质我们可以知道它的dfs树只有返祖边.考虑下面这样一个结论. 结论:若一个点的子树中(包含自己)有两个点有到它祖先的返祖边(不包括到它自己), 首先我们证明S和T肯定在DFS树中是祖先关系,接着证明到T至少有一条返祖边,那么这个结论就是显然的了. 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 102000; 5

hihocoder 1192 简单的树嵌入 (树上DFS 构造 好题)

#1192 : 简单的树嵌入 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一棵n个点的无权树.定义两点i,?j(0?≤?i,?j?≤?n?-?1)间的距离d(i,?j)为两点间树上最短路径的长度(边数). 我们需要将这n个点映射到中的向量v0?=?(v0,?0,?...,?v0,?m?-?1),?...,?vn?-?1?=?(vn?-?1,?0,?...,?vn?-?1,?m?-?1).定义两向量vi,?vj间的L1距离为 我们希望对于所有0?≤?i,?j?