p1268树的重量 题解

题面描述点此qwq。

正解开始。

一道茅塞顿开恍然大悟的题目:

第一眼看到这个题的时候,语文不好的我对着题目中的

这些,和:

这句话发呆半天,,,,

因为不关我怎么构建几何模型,我都不理解这句话。。

(吐槽题面臃肿!)

然后想了一下,发现题目是这个亚子:

给你一个矩阵M,M上每一个节点(i,j)表示叶子结点i和叶子结点j的距离,每个矩阵有且只能生成唯一一个树(不然这题没法搞了),让你求这棵树上的每一条边的权值和。

在李姐(lz dalao)完题目之后,我又开始懵了。。。。。。到底怎么搞非叶节点的位置???暴力恐怕不行的。。

百思不得其解后,我在绝望中从最简单情况递推:

考虑只有两个(n=2)节点1,2,一条边权值为3

这种情况:

那么,两个节点自然权值就为3了,答案也是3。

一旦跨越到n=3这种情况,就有些棘手。

因为3个节点都是叶子结点,那么必然要在1到2的路径上选一个中间节点来连接3号节点。

(选哪里好呢..?)

因为1到3和2到3的长度都知道了,那么我们可以利用数学方法求助3的位置。

假设M[1][3]=4,M[2][3]=3,那么这两条路径必然有和1到2的路径重复的

那么我们减去重复的,就是3节点到1,2路径的距离了。

如图:

公式:(jz[1][3]+jz[2][3]-jz[1][2])/2=(4+3-3)/2=2.

那么,理解了这个以后,我们可以顺着推n>3的情况:

从之前n-1的情况中找两个点之间的路径,并尝试插入当前节点,然后取min。

节点太多就不画了。。

上代码吧。。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

inline int read()
{
    int ans=0;
    char ch=getchar(),last=‘ ‘;
    while(ch<‘0‘||ch>‘9‘)last=ch,ch=getchar();
    while(ch>=‘0‘&&ch<=‘9‘)ans=(ans<<3)+(ans<<1)+ch-‘0‘,ch=getchar();
    return last==‘-‘?-ans:ans;
}

int n,jz[100][100];

int main(){
    n=read();
    while(n!=0)
    {
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                jz[j][i]=read(),jz[i][j]=jz[j][i];
        int ans=jz[1][2];
        for(int i=3;i<=n;i++)
        {
            int dt=0x3f3f3f3f;
            for(int j=1;j<=i-1;++j)
                for(int k=1;k<=j-1;++k)
                {
                    dt=min(dt,(jz[j][i]+jz[k][i]-jz[j][k])>>1);
                }
        ans+=dt;
        }
        printf("%d\n",ans);
        n=read();
    }
}

完结。

原文地址:https://www.cnblogs.com/lbssxz/p/11402768.html

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

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 树的重量【构造】

题目描述 树可以用来表示物种之间的进化关系.一棵“进化树”是一个带边权的树,其叶节点表示一个物种,两个叶节点之间的距离表示两个物种的差异.现在,一个重要的问题是,根据物种之间的距离,重构相应的“进化树”. 令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的最短路径长度. 如下图

HDU 1754 I hate it 分段树Segment Tree题解

给出一段数据,然后要更新单个数据,会询问一段数据中的最大值. 又是一道分段树操作.渐渐熟手了. #pragma once #include <cstdio> #include <algorithm> using namespace std; class IHateIt_1754_1 { static const int SIZE = 200001; int *segTree; //不要使用segTree[SIZE<<2] inline int lChild(int r)

CODEVS 1081 线段树练习 2 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:http://codevs.cn/problem/1081/ 题目描述 Description 给你N个数,有两种操作 1:给区间[a,b]的所有数都增加X 2:询问第i个数是什么? 输入描述 Input Description 第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,表示操作的个数. 接下来Q行每行若干个整数.如果第一个数是1,后接3个正整数a,b,X,表示在区间[a,b]内每个数增加X,如果

Codeforces 750E New Year and Old Subsequence 线段树 + dp (看题解)

New Year and Old Subsequence 第一感觉是离线之后分治求dp, 但是感觉如果要把左边的dp值和右边的dp值合起来, 感觉很麻烦而且时间复杂度不怎么对.. 然后就gun取看题解了, 用线段树维护dp的值, 然后区间合并求答案. 每个节点保存dp[ i ][ j ]表示, 把当前管理的区间删到 s{2017}中的 s[ i + 1 ] - s[ j - 1 ],最少删几个, 然后合并的时候5 ^ 3合并. #include<bits/stdc++.h> #define L

HUT 线段树练习 部分题解

F-poj 2886 这题去年月神给我们14级的抓过.然而比较偏数学. 题意大概是n个小朋友围成一圈,每个小朋友手里都有一张卡片,卡片上有个数字a[i]. 从第k个小朋友开始,第k个小朋友出圈,然后让他的左手方向的第a[k]个小朋友出圈.然后这个小朋友又根据规则让另一个小朋友出圈. 第p个出圈的小朋友拿到的糖果数目为p的因子个数,问谁拿到了最多的糖果 可以打反素数表的方式来做(百度即可),但这里介绍另一种方法,就是我们可以直接dfs出小于n的,因子个数最多的数 因为要使因子个数尽量的多,该数应该

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]

树套树三题 题解

1.COGS 1534 [NEERC 2004]K小数 其实是主席树裸题…… (其实这题数据非常水……从O(nlogn)的主席树到O(nlog3n)的树套树+二分到O(nsqrt(n)log2n)的分块套二分套二分到O(n2)的暴力都能过……) 鉴于这就是动态排名系统的静态版,就不说了,贴代码: 线段树套平衡树: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; con