题意是删除一些边使原图剩P个节点,那么我们在进行树形dp的时候就要考虑这条是不是删,但这样就不太好转移。
那么我们转化一下,假设把所有的边先都删除,那么我们要考虑这条边是不是要加进去,这要就好转移多了,就是一个背包+树形dp。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; inline int read(){ char ch = getchar(); int f = 1 , x = 0; while(ch > '9' || ch < '0'){if(ch == '0') f = -1;ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();} return x * f; } int n,p,u,v; struct Edge{ int from,to,next; }edge[200 * 2]; int head[200],tot; int du[200],f[200][200],ans=1e9; //f[i][j]:表示以i为根的子树里面截取j个节点的最少删边数 void add(int u,int v){ edge[++tot].from = u; edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot; } void dfs(int x,int fa){ if(fa != 0) f[x][1] = du[x] - 1; else f[x][1] = du[x]; for(int i=head[x];i;i=edge[i].next){ int v = edge[i].to; if(v != fa){ dfs(v , x); for(int j=p;j>=1;j--) for(int k=1;k<j;k++) f[x][j] = min(f[x][j] , f[x][k] + f[v][j-k] - 1); //减1因为一开始把所有的边都删了 } } if(fa != 0) ans = min(ans , f[x][p] + 1); else ans = min(ans , f[x][p]); } int main(){ n = read(); p = read(); for(int i=1;i<=n-1;i++){ u = read(); v = read(); add(u , v); add(v , u); du[u]++; du[v]++; } memset(f , 0x3f , sizeof(f)); dfs(1 , 0); printf("%d ",ans); return 0; }