基礎演算法 重建道路

2021-09-12 14:00:53 字數 1471 閱讀 2190

題目

描述 輸入

輸出 樣例輸入

樣例輸出 分析

**一場可怕的**後,人們用n個牲口棚(1≤n≤150,編號1..n)重建了farmer john的牧場。由於人們沒有時間建設多餘的道路,所以現在從乙個牲口棚到另乙個牲口棚的道路是惟一的。因此,牧場運輸系統可以被構建成一棵樹。

john想要知道另一次**會造成多嚴重的破壞。有些道路一旦被毀壞,就會使一棵含有p(1≤p≤n)個牲口棚的子樹和剩餘的牲口棚分離,john想知道這些道路的最小數目。

例如,如圖所示的牧場,要求p=6。如果道路1-4和1-5被破壞,含有節點(1,2,3,6,7,8)的子樹將被分離出來。

第1行:2個整數,n和p 

第2..n行:每行2個整數i和j,表示節點i是節點j的父節點。

第1行:1個整數,表示一旦被破壞將分離出恰含p個節點的子樹的道路的最小數目。

11 6

1 21 3

1 41 5

2 62 7

2 84 9

4 10

4 11

2
根據題意,很容易設計出狀態

dp[i][j]:在以 i 為樹根的子樹中分離出 j 個節點需要砍斷路徑數的最小值

顯然,當j = 1時,dp[i][j] = i 的兒子數;

又因為他需要求最小值,所以dp的初始化為極大值。

and,狀態轉移方程為

後面跟了個減二,很神奇吧……

具體原因:

顯然我們處理的時候並沒有考慮父親(也就是假設 i 點沒有與父親相連),但顯然我們在初始化的時候 i 就加上了

而同理,son也算了

#include#include#include#include#define m 150

#define reg register

using namespace std;

int n,m,d[m + 5],dp[m + 5][m + 5];

vector < int > g[m + 5];

void dfs(int x,int fa)

}int main()

memset(dp,0x3f,sizeof(dp));

for (reg int i = 1;i <= n; ++ i)

dp[i][1] = d[i];

dfs(1,0);

int ans = dp[1][m];

for (reg int i = 2;i <= n; ++ i)

if (dp[i][m] <= ans)

ans = dp[i][m];

printf("%d\n",ans);

return 0;

}

1686 道路重建

時間限制 1 sec 記憶體限制 128 mb 提交 11 解決 7 提交 狀態 討論版 現在有一棵n個結點的樹 結點從1到n編號 請問至少要刪除幾條邊,才能得到乙個恰好有p個結點的子樹?第一行輸入兩個數n和p 1 n 150,1 p n 接下來輸入n 1行,每行兩個整數x y,表示x和y之間有一條...

重建道路 樹上揹包

初始化 void init struct edges edge maxm 1 無向圖則需要乘2 inline void add int u,int v head u cnt int dp m m siz m tmp m int n,m void dfs int u,int fa siz u siz ...

P3905 道路重建

p3905 道路重建 我一開始想錯了,我的是類似kruskal,把毀壞的邊從小到大加,並且判斷聯通性。但是這有乙個問題,你可能會多加,就是這條邊沒用,但是它比較小,你也加上了。居然還有10分,資料也是水水的。include include include include include includ...