題面描述點此qwq。ios
正解開始。spa
一道茅塞頓開恍然大悟的題目:3d
第一眼看到這個題的時候,語文很差的我對着題目中的code
這些,和:blog
這句話發呆半天,,,,get
由於不關我怎麼構建幾何模型,我都不理解這句話。。數學
(吐槽題面臃腫!)string
而後想了一下,發現題目是這個亞子:io
給你一個矩陣M,M上每個節點(i,j)表示葉子結點i和葉子結點j的距離,每一個矩陣有且只能生成惟一一個樹(否則這題無法搞了),讓你求這棵樹上的每一條邊的權值和。ast
在李姐(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(); } }
完結。