这题我不看题解是真的不会,我还是太弱了
题意:给定一棵树的n个叶子节点之间的最短路径,且
g[i][j]+g[j][k]≥g[i][k]
g
[
i
]
[
j
]
+
g
[
j
]
[
k
]
≥
g
[
i
]
[
k
]
,需要求出满足条件的树的边权和(我们不必在乎点具体所在位置,只需考虑长度的贡献)。
首先不难想到的是当
n=2
n
=
2
时,显然答案为
g[1][2]
g
[
1
]
[
2
]
。
而当
n=3
n
=
3
时,因为要满足标号节点均为叶子节点,所以多出的3号叶子节点必定只能由
g[1][2]
g
[
1
]
[
2
]
之间多出一条分枝相连。
所以此时对答案的贡献就是
g[1][3]+g[2][3]−g[1][2]2
g
[
1
]
[
3
]
+
g
[
2
]
[
3
]
−
g
[
1
]
[
2
]
2
。
当
n=4
n
=
4
时,还是得满足均为叶子节点的限制,所以多出的节点显然只能在
g[1][2]或g[1][3]或g[2][3]
g
[
1
]
[
2
]
或
g
[
1
]
[
3
]
或
g
[
2
]
[
3
]
这三条分枝上再接一条分枝与
4
4
相连。
所以此时对答案的贡献就是
所以我们从第三个点开始枚举,作为新加入的点,对于每次枚举到的 i i 号节点,然后枚举在前个节点互相之间的路径上多出分枝的情况,取最小值累加即可。
#include<bits/stdc++.h>
using namespace std;
int g[2000][2000],n,ans;
int main()
{
while(scanf("%d",&n))
{
if(n==0)
return 0;;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
scanf("%d",&g[i][j]);
g[j][i]=g[i][j];
}
ans=g[1][2];
for(int i=3;i<=n;i++)
{
int dis=1000000000;
for(int j=1;j<=i-1;j++)
for(int k=1;k<=j-1;k++)
dis=min(dis,(g[i][j]+g[i][k]-g[j][k])/2);
ans+=dis;
}
printf("%d\n",ans);
}
return 0;
}