进化树问题
Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^
题目描述
在生物学中,树可以用来表示物种之间的进化关系,这样的树称为进化树。在进化树上每个叶子结点代表一个物种,如果每一条边都被赋予一个适当的权值,那么两个叶子结点之间的最短距离就可以表示相应的两个物种之间的差异程度。生物学家Dr.Lee的一项重要工作就是根据实验得到的物种间差异程度数据来构造出进化树,从而了解物种的进化过程。但是用人手工做这项工作实在太慢,他不得不请你这位计算机专家来编写程序减轻他的负担。
Dr.Lee选定了n个物种,并从1到n进行编号,然后他对每两个物种进行比较,得到它们的差异程度值,并记录在一个n*n的差异程度表M里面。在表M中,第i行第j列的数据M[i,j]表示物种i和物种j之间的差异程度。Dr.Lee还总结出了关于进化树的几条规律:
(1)进化树有且只有n个叶子,第i个叶子对应物种i;
(2)每条边上的权值都是非负整数;
(3)M[i,j]就是进化树上叶子i和叶子j之间的最短距离,满足M[i,j]=0,M[i,j]=M[j,i],而且满足三角不等式:对任意的i,j,k,总有M[i,j]+M[j,k]≥M[i,k]。
例如,对于如图1所示的进化树,可以得到相应的差异程度表M如图2所示。
定义进化树的规模为该树所有边的权值之和。Dr.Lee发现,对同一个差异程度表M,所对应的进化树的规模总是固定的。换句话说,如果两颗进化树的规模不相等,那么它们各自对应的差异程度表也会有所不同。现在你的任务就是编写程序,对于给定的差异程度表M,给出对应的进化树的规模。
输入
输入第1行为一个正整数n,2<=n<=100;接下来的n-1行表示差异程度表的上三角部分(不包括对角线),其中第i行(2<=i<=n)有n+1-i个数,表示编号为i-1的物种与所有编号大于i-1的物种之间的差异程度值。同一行的数与数之间用空格隔开,每个数都是不超过1000000的非负整数。
输出
输出只有一个整数,就是对应进化树的规模。
示例输入
示例输出
15
分析:对于两个点,总和就是两点的距离;对于三个点A,B,C,设内点DA到B或者C必须要经过AD,AD=|AC+AB-BC|/2;
对于n个点就要枚举删除的点,直到最后就剩下两个点;
程序:
#include"stdio.h"
#include"string.h"
#include"queue"
#include"stack"
#include"algorithm"
#include"vector"
#include"iostream"
#include"math.h"
#include"map"
#include"stdlib.h"
#define M 222
#define inf 100000000
using namespace std;
int G[M][M],dis[M];
int main()
{
int n,i,j,k;
while(scanf("%d",&n)!=-1)
{
memset(G,0,sizeof(G));
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
{
scanf("%d",&G[i][j]);
G[j][i]=G[i][j];
}
}
int ans=0;
/*for(i=1;i<n-1;i++)
{
int mini=inf;
for(j=i+1;j<=n;j++)
{
for(k=j+1;k<=n;k++)
{
int t=(G[i][j]+G[i][k]-G[j][k])/2;
mini=min(mini,t);
}
}
ans+=mini;
}*/
for(i=1;i<n-1;i++)
{
int mini=inf;
j=i+1;
for(k=j+1;k<=n;k++)
{
int t=(G[i][j]+G[i][k]-G[j][k])/2;
mini=min(mini,t);
}
ans+=mini;
}
ans+=G[n-1][n];
printf("%d\n",ans);
}
}