BJ模擬 tree 樹形dp

2021-08-19 17:34:16 字數 1689 閱讀 9226

題目描述:

給一棵

n n

個節點的邊帶權樹,要求在樹上選出

k' role="presentation" style="position: relative;">k

k個點 a1

,a2,

...,

aka 1,

a2,.

..,a

k,使得 ∑k

−1i=

1dis

(ai,

ai+1

) ∑i=

1k−1

dis(

ai,a

i+1)

最小。1≤

k≤n≤

3000

1 ≤k

≤n

≤3000

解題思路:

首先答案一定是乙個連通子樹,且為2*子樹邊權和-子樹直徑長度。

這樣就比較好dp了。g[

x][i

] g[x

][i]

表示以

x x

為根的子樹中選了

i' role="presentation" style="position: relative;">i

i個點且包含

x x

(下面都是這樣)的最小邊權和的兩倍,f0

[x][

i]' role="presentation" style="position: relative;">f0[

x][i

]f0[

x][i

]表示直徑一端為

x x

,f1[x][

i]' role="presentation" style="position: relative;">f1[

x][i

]f1[

x][i

]表示

x x

不是直徑一端的最優值,按定義轉移即可,dp性質可以保證選的直徑確實是真直徑。

時間複雜度為o(

n2)' role="presentation" style="position: relative;">o(n

2)o(

n2)

#include

#define ll long long

using namespace std;

int getint()

const int n=3005,inf=0x3f3f3f3f;

int n,k,ans=inf,size[n],g[n][n],f0[n][n],f1[n][n];

int tot,first[n],nxt[n<<1],to[n

<<1],w[n

<<1];

void

add(int

x,int

y,int

z)void

checkmin(int &x,int

y)void

dfs(int

u,int

fa) size[u]+=size[v];

}}int

main()

dfs(1,0);

for(int

i=1;i<=n;i++)if(size[i]>

=k)ans=min(ans,min(f0[i][k],f1[i][k]));

cout}

HDU 3534 Tree 樹形dp統計

題意 給定n 範圍不明確,不過10000可以過 個點的樹,問樹的直徑有多少條。題解 維護乙個子根節點到子樹中葉子節點的最長路,次長路和對應的個數,注意路之間不能在同一棵子樹內,然後統計每棵子樹的直徑,最後遍歷得到答案。include include include using namespace s...

HDU 3534 Tree 經典樹形dp

題意 在一棵樹上找最長路徑,和他出現的個數。思路 有做過poj1985 求樹直徑 的基礎,我們知道我們一遍dfs可以得到dp i 表示i點為根的子樹到葉子的最長距離,次長距離,同時我們還可以記載他們出現的數量。我們可以先簡單的分析,定義dp i 0 dp i 1 i點為根到葉子的最長,次長距離,dp...

HDU 3534 Tree 經典樹形dp

題意 給你一棵樹,問你有多少對點的距離等於樹的直徑。思路 dp i 0 表示在i的子樹中 離i最遠的距離,dp i 1 是次遠距離。cnt i 0 則是最遠的點的數量,cnt i 1 表示次遠的數量。up i 表示以i向上 離i最遠的距離。up cnt i 表示向上最遠的數量。寫的有點麻煩,除錯了2...