[枚舉]Luogu P1268 樹的重量
阿新 • • 發佈:2018-03-16
load 輸出格式 對角線 最短路徑 技術 pos -o 定義 我們
題目描述
樹可以用來表示物種之間的進化關系。一棵“進化樹”是一個帶邊權的樹,其葉節點表示一個物種,兩個葉節點之間的距離表示兩個物種的差異。現在,一個重要的問題是,根據物種之間的距離,重構相應的“進化樹”。
令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-l行,給出的是矩陣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
題解
- 盜用一張圖先
- 這張圖的樹的重量為(1,2)+藍色部分
- 那麽藍色部分怎麽求?
- 發現,(1,3)和(2,3)都是經過藍色部分的
- 把它們相加發現:(1,2)+2*藍色部分
- 而且已知(1,2),藍色部分就用容易求
- 用字母表示就是:((1,i)+(j,i)-(1,j))/2
- 解決這個問題後,考慮怎麽構造樹
- 這棵樹要滿足:
- ①符合矩陣 ②每條邊都要加一次,而且最多一次
- 假如我們前i-1個都構造完了,那麽怎麽構造i個
- 題目要求重量要盡量小,顯然就枚舉加入哪條邊中,取最小值
- Ojbk!!
代碼
1 #include<cstdio> 2 #include<iostream> 3 using namespacestd; 4 const int inf=(1<<30); 5 int d[60][60],n; 6 int main() 7 { 8 while(scanf("%d",&n)==1&&n) 9 { 10 for(int i=1;i<=n;i++) 11 for(int j=i+1;j<=n;j++) 12 scanf("%d",&d[i][j]),d[j][i]=d[i][j]; 13 int ans=d[1][2]; 14 for(int i=3;i<=n;i++) 15 { 16 int t=inf; 17 for(int j=2;j<i;j++) t=min(t,(d[1][i]+d[j][i]-d[1][j])/2); 18 ans+=t; 19 } 20 printf("%d\n",ans); 21 } 22 return 0; 23 }
[枚舉]Luogu P1268 樹的重量