#P2870. USACO(125)动态规划(树形DP)3:切断道路[Rebuilding Roads, Feb 2002]

USACO(125)动态规划(树形DP)3:切断道路[Rebuilding Roads, Feb 2002]

Description

【题意】
约翰有 N 个牛棚,这些牛棚间有 N − 1 条双向道路。第 i 条道路连接了第 Ai 个牧场和第 Bi 个牧场,Ai 和 Bi 被称为邻居。任意两牛棚都可以通过道路连通。
约翰得到消息,洪水将要到来了,于是他打算把奶牛集中安置到避难点。避难点必须由相邻的 P个牛棚组成。他还要切断这些牛棚和其他牛棚之间的道路。请问约翰该选择哪些牛棚作为避难点,才能使得需要切断的道路最少呢?

【输入格式】
第一行:两个整数 N 和 P,1 ≤ P ≤ N ≤ 150。
第二行到 N 行:第 i + 1 行有两个整数:Ai 和 Bi,1 ≤ Ai, Bi ≤ N。

【输出格式】
单个整数,表示需要切断的道路数量。

【样例输入】
11 6
1 2
1 3
1 4
1 5
2 6
2 7
2 8
4 9
4 10
4 11

【样例输出】
2

【解释】
选择 {1, 2, 3, 6, 7, 8},需要切断的是 (1, 4) 和(1, 5)

Hint

#include<bits/stdc++.h>
using namespace std;
const int N=200;
int f[N][N], d[N], n, p;
vector<int> G[N];
void dfs(int x, int fa){
	f[x][1]=d[x];
	for(int y: G[x]) if(y!=fa){
		dfs(y, x);
		for(int i=p; i>=1; i--){
			for(int j=1; j<i; j++){
				f[x][i]=min(f[x][i], f[x][j]+f[y][i-j]-2);
			}
		}
	}
}
int main(){
	scanf("%d%d", &n, &p);
	memset(d, 0, sizeof(d));
	for(int i=1; i<n; i++){
		int x, y; scanf("%d%d", &x, &y);
		G[x].push_back(y);
		G[y].push_back(x);
		d[x]++; d[y]++; 
	} 
	memset(f, 0x3f, sizeof(f));
	dfs(1, 0);
	int ans=0x3f3f3f3f;
	for(int i=1; i<=n; i++) ans=min(ans, f[i][p]);
	printf("%d\n", ans);
	return 0;
}