poj 1947 树形dp
思路:dp[i][j]表示,以i节点为根,删去j个节点最少要断几条边。
那么dp[u][j]=min(dp[u][j],dp[v][k]+dp[u][j-k]);//选取最优状态
dp[u][j]=min(dp[u][j],dp[u][j-son[v]]+1);//切断与子节点相连的边
对于子节点
dp[v][n-son[v]]=1;
dp[v][j]=min(dp[v][j],dp[v][j-n+son[v]]+1)//表示不需要由父节点过来的那条分支
最有从所有状态中选举最优的dp[i][n-p];
#include<map> #include<set> #include<cmath> #include<queue> #include<cstdio> #include<vector> #include<string> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define Maxn 160 #define Maxm 200010 #define LL __int64 #define Abs(x) ((x)>0?(x):(-x)) #define lson(x) (x<<1) #define rson(x) (x<<1|1) #define inf 0x7fffffff #define Mod 1000000007 using namespace std; int head[Maxn],vi[Maxn],e,dp[160][160],n,p,son[160],root[Maxn]; struct Edge{ int u,v,next; }edge[Maxm]; void init() { memset(head,-1,sizeof(head)); memset(vi,0,sizeof(vi)); memset(son,0,sizeof(son)); for(int i=1;i<=155;i++){ root[i]=i; for(int j=1;j<=155;j++){ dp[i][j]=200; } dp[i][0]=0; } e=0; } void add(int u,int v) { edge[e].u=u,edge[e].v=v,edge[e].next=head[u],head[u]=e++; edge[e].u=v,edge[e].v=u,edge[e].next=head[v],head[v]=e++; } void dfs(int u) { int i,v,j,k; vi[u]=1; son[u]=1; for(i=head[u];i!=-1;i=edge[i].next){ v=edge[i].v; if(vi[v]) continue; dfs(v); son[u]+=son[v]; for(j=n-1;j>=1;j--){ for(k=1;k<=j;k++){ dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]); } if(j>=son[v]) dp[u][j]=min(dp[u][j],dp[u][j-son[v]]+1); } dp[v][n-son[v]]=1; for(j=n-1;j>=n-son[v];j--) dp[v][j]=min(dp[v][j],dp[v][j-n+son[v]]+1); } } int main() { int i,j,u,v; while(scanf("%d%d",&n,&p)!=EOF){ init(); for(i=1;i<n;i++){ scanf("%d%d",&u,&v); add(u,v); } if(p==n){ printf("0\n"); continue; } if(p==n-1) { printf("1\n"); continue; } dfs(1); int ans=200; for(i=1;i<=n;i++){ ans=min(ans,dp[i][n-p]); } printf("%d\n",ans); } return 0; }