題目
描述 輸入
輸出 樣例輸入
樣例輸出 分析
**一場可怕的**後,人們用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...