http://poj.org/problem?id=1947
给你一棵n个节点的树 问你保存p个节点的子树最少需要切断多少条边
我用邻接表保存树
ans[i][j] 代表了包含i在内的它所要子节点和兄弟子树在内 保存j个点需要最少切断多少边
代码及其注释:
#include<iostream> #include<stdio.h> #include<string.h> #include<queue> #include<cmath> #include<stack> #include<algorithm> #define LL long long using namespace std; const int N=155; const int M=1000001; struct node { struct tt *next; }mem[N]; struct tt { int j; struct tt *next; }; int ans[N][N]; void build(int i,int j) { struct tt *t=new tt; t->j=j; t->next=mem[i].next; mem[i].next=t; } void Dele(int n) { struct tt *t; for(int i=1;i<=n;++i) { while(mem[i].next!=NULL) { t=mem[i].next; mem[i].next=t->next; delete t; } } } int dp(struct tt *t,int k) { if(t==NULL)//如果为空了 { if(k==0)//保存0个的话反回0 return 0; else return M;//否则反回最大 } if(ans[t->j][k]!=-1) return ans[t->j][k]; if(k==0)//保存0 个的话 需要切断所以兄弟节点与负节点的连线 { ans[t->j][k]=1+dp(t->next,k); return ans[t->j][k]; } ans[t->j][k]=1+dp(t->next,k);//此节点子树与父节点切断 for(int i=1;i<=k;++i) { //递归找最优 ans[t->j][k]=min(ans[t->j][k],dp(mem[t->j].next,i-1)+dp(t->next,k-i)); } return ans[t->j][k]; } int main() { int n,k; while(scanf("%d %d",&n,&k)!=EOF) { for(int i=1;i<n;++i) { int x,y; scanf("%d %d",&x,&y); build(x,y); } if(n==1) { printf("0\n"); continue; } int MIN=M; memset(ans,-1,sizeof(ans)); MIN=min(MIN,dp(mem[1].next,k-1)); for(int i=2;i<=n;++i) { MIN=min(MIN,1+dp(mem[i].next,k-1));//不一定值保存 1 } printf("%d\n",MIN); Dele(n); } }