Rebuilding Roads
分類:
dfs and similar
trees
dp
1.題意概述
- 給你一顆有
n 個節點構成是樹,現在要你刪去最少的邊,使得剩下連通的點構成的樹剛好有p 個節點。
2.解題思路
- 容易想到是一個樹形dp,
dp[i][j] 表示以i 節點爲根節點,得到j 個節點的子樹需要去掉的最少邊數,那麼轉移方程爲:考慮其兒子k 選或者不選——最後取個最小值就行
- 如果不去掉
k 的子樹:dp[s][i]=min(dp[s][j]+dp[k][i−j]),0≤j≤i - 如果去掉
k 的子樹:dp[s][i]=dp[s][i]+1
- 如果不去掉
3.AC代碼
#define N 152
int f[N][N], sonA[N], sonB[N];
bool pa[N];
int n, p;
void init() {
memset(pa, 0, sizeof pa);
memset(sonA, 0, sizeof sonA);
memset(sonB, 0, sizeof sonB);
}
void dfs(int u) {
fill(f[u], f[u] + p + 1, INF);
f[u][1] = 0;
int k = sonA[u];
while (k) {
dfs(k);
per(i, 1, p + 1) {
int tmp = f[u][i] + 1;
rep(j, 1, i)
tmp = min(tmp, f[k][i - j] + f[u][j]);
f[u][i] = tmp;
}
k = sonB[k];
}
// rep(i, 1, p + 1) printf("%d ", f[u][i]);
// puts("");
}
int main() {
while (~scanf("%d%d", &n, &p)) {
init();
rep(i, 1, n) {
int u, v;
scanf("%d%d", &u, &v);
pa[v] = 1;
sonB[v] = sonA[u];
sonA[u] = v;
}
int sta = 0;
rep(i, 1, n + 1)
if (!pa[i]) {
sta = i;
break;
}
dfs(sta);
int ans = f[sta][p];
rep(i, 1, n + 1) {
if (i != sta)
ans = min(ans, f[i][p] + 1);
}
printf("%d\n", ans);
}
return 0;
}