1686 道路重建

2021-09-07 15:35:59 字數 1648 閱讀 5478

時間限制: 1 sec  記憶體限制: 128 mb

提交: 11  解決: 7 [

提交][

狀態][

討論版]

現在有一棵n個結點的樹(結點從1到n編號),請問至少要刪除幾條邊,才能得到乙個恰好有p個結點的子樹?

第一行輸入兩個數n和p (1 <= n<= 150, 1 <= p<= n)

接下來輸入n-1行,每行兩個整數x y,表示x和y之間有一條邊。

輸出答案。

11 6

1 21 3

1 41 5

2 62 7

2 84 9

4 10

4 11

2
如果1-4 和 1-5 兩條邊刪除,結點1, 2, 3, 6,

7, 8會形成一顆有6個結點的子樹。

分析:

之前方法不對的乙個題。樹形dp。

數型dp總結一下。

用 dp[i][j] 表示以i節點為根,截出含有j個點的連通子樹所需要截的最少次數。

那麼可以得到初始化 dp[i][1]=du[i] (du[i]為i的入邊與出邊的總和),意思是只選i這乙個節點,那麼當然要把與它相連的邊都截掉。

那麼狀態轉移方程怎麼得到呢

以樣例為例子,節點1連線 2,3,4,5 。節點2連線 6,7,8。遞迴著進行動規之後我們可以得到 dp[2][3]=2 (擷取1-2和2-8)

那麼dp[1][4]=min(dp[1][4],dp[2][3]+dp[1][1]-2)

為啥要減2

因為dp[1][1]是刪了一次 1-2 的結果,dp[2][3]也刪了一次 1-2,但事實上得到dp[1][4]時 1-2是連通的,所以把這刪的兩次補上。

具體動規按照分組揹包的迴圈順序跑。

狀態轉移方程:

dp[u][j]=min(dp[u][j],dp[u][k]+dp[v][j-k]-2);

從父親節點選k個,從兒子節點擊j-k個。

1 #include2 #include3 #include4 #include5 #include6

#define ll long long

7#define m(a) memset(a,0,sizeof a)

8#define fo(i,j,k) for(i=j;i<=k;i++)

9using

namespace

std;

10const

int mxn=155

;11 vector f[mxn];

12int

n,p;

13int

dp[mxn][mxn],du[mxn];

14 inline void dfs(int

u)1527}

28int

main()

2940 dfs(1

);41 fo(i,1

,n)42 ans=min(ans,dp[i][p]);

43 printf("

%d\n

",ans);

44return0;

45 }

基礎演算法 重建道路

題目 描述 輸入 輸出 樣例輸入 樣例輸出 分析 一場可怕的 後,人們用n個牲口棚 1 n 150,編號1.n 重建了farmer john的牧場。由於人們沒有時間建設多餘的道路,所以現在從乙個牲口棚到另乙個牲口棚的道路是惟一的。因此,牧場運輸系統可以被構建成一棵樹。john想要知道另一次 會造成多...

重建道路 樹上揹包

初始化 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...