1. 程式人生 > >P1268 樹的重量

P1268 樹的重量

amp 數據包 差異 lin 矩陣 inline 現在 有意 輸出格式

題目描述

樹可以用來表示物種之間的進化關系。一棵“進化樹”是一個帶邊權的樹,其葉節點表示一個物種,兩個葉節點之間的距離表示兩個物種的差異。現在,一個重要的問題是,根據物種之間的距離,重構相應的“進化樹”。

令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

Solution:

  本題很有意思的思維題(話說期末考崩了啊,本來想數學拉分的,結果數學也炸了,好崩心態啊!滾粗搞競賽!)。

  題意等價於給定一棵樹的$n$個葉子節點之間的最短路徑,且$d[i][j]+d[j][k]\geq d[i][k]$,需要求出滿足條件的樹的邊權和(我們不必在乎點具體所在位置,只需考慮長度的貢獻)。

  首先不難想到的是當只有兩個葉子節點時,顯然答案為$d[1][2]$。

  而當$n==3$時,因為要滿足標號節點均為葉子節點,所以多出的$3$號葉子節點必定只能由$G[1][2]$之間多出一條分枝相連,如圖:

  技術分享圖片

  那麽多出的分枝長度顯然為$\frac{d[1][3]+d[2][3]-d[1][2]}{2}$。

  當$n==4$時,還是得滿足均為葉子節點的限制,所以多出的節點顯然只能在$G[1][2]$或$G[1][3]$或$G[2][3]$這三條分枝上再接一條分枝與$4$相連,如圖:

  技術分享圖片

  容易發現,此時多出的長度為$min(\frac{d[1][4]+d[2][4]-d[1][2]}{2},\frac{d[1][4]+d[3][4]-d[1][3]}{2},\frac{d[2][3]+d[3][4]-d[2][4]}{2})$。

  不難發現每次多出的$n$號節點,需要枚舉在前$n-1$個節點互相之間的路徑上多出分枝的情況,取最小值累加。

  那麽實現時直接模擬就好了。

代碼:

 1 #include<bits/stdc++.h>
 2 #define il inline
 3 #define ll long long
 4 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
 5 #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
 6 using namespace std;
 7 int n,mp[31][31],ans,tp;
 8 
 9 il int gi(){
10     int a=0;char x=getchar();
11     while(x<0||x>9)x=getchar();
12     while(x>=0&&x<=9)a=(a<<3)+(a<<1)+x-48,x=getchar();
13     return a;
14 }
15 
16 int main(){
17     while(scanf("%d",&n)!=EOF&&n){
18         For(i,1,n-1) For(j,i+1,n) mp[i][j]=mp[j][i]=gi();
19         ans=mp[1][2];
20         For(i,3,n){
21             tp=0x7fffffff;
22             For(j,1,i-1) For(k,1,j-1)
23                 tp=min(tp,(mp[j][i]+mp[k][i]-mp[j][k])>>1);
24             ans+=tp;
25         }
26         printf("%d\n",ans);
27     }
28     return 0;
29 }

P1268 樹的重量