p1268樹的重量 題解

題面描述點此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();
    }
}

完結。

相關文章
相關標籤/搜索