题目链接:http://poj.org/problem?id=1947
题意:给n(n<=150)个点的一棵树,求删掉最少边数k使得最后该树只剩下p(1<=p<=n)个节点。(求最小的k)
分析:设dp[u][j]表示以u节点为根的子树保留j个节点删掉最少的边数;则dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]).初始值dp[u][1]=0.
#include <cstdio> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> #include <queue> #include <cstdlib> #include <stack> #include <vector> #include <set> #include <map> #define LL long long #define mod 1000000007 #define inf 0x3f3f3f3f #define N 250 #define clr(a) (memset(a,0,sizeof(a))) using namespace std; struct edge { int next,v; edge(){} edge(int v,int next):v(v),next(next){} }e[N*2]; int head[N],tot,n,m; int dp[N][N]; void addedge(int u,int v) { e[tot]=edge(v,head[u]); head[u]=tot++; } void dfs(int u,int fa) { dp[u][1]=0; for(int i=head[u];~i;i=e[i].next) { int v=e[i].v; if(v==fa)continue; dfs(v,u); for(int j=m;j>=1;j--) { dp[u][j]++;//对于子树u,要保持j个节点不变,必须砍掉该条边去掉子树v for(int k=1;k<j;k++) dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]); } } } int main() { int u,v; while(scanf("%d%d",&n,&m)>0) { tot=0; memset(head,-1,sizeof(head)); memset(dp,0x3f,sizeof(dp)); for(int i=1;i<n;i++) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } dfs(1,-1); int ans=dp[1][m]; for(int i=2;i<=n;i++)ans=min(ans,dp[i][m]+1); printf("%d\n",ans); } }
时间: 2024-10-30 01:56:09