POJ1947 Rebuilding Roads

来源:互联网 发布:java培训出来找工作 编辑:程序博客网 时间:2024/04/30 09:53

树形dp!!!关键是枚举s点的所有的不去掉k子树的情况!!!

 

因为是树形DP,而子问题往往涉及的是子树的信息,所以我们要对树先进行深搜,求出子问题的解,然后再返回根节点,求根节点的信息。。。



#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<string>#include<algorithm>#include<memory.h>#include<queue>#include<stack>#define maxn 155using namespace std;int n,p;int son[maxn],blo[maxn],hf[maxn];//son[i]为i的儿子blo[i]为i的兄弟,hf[i]表示i是否有父亲int dp[maxn][maxn];//dp[i][j]表示以i为根得到j个点的子树(不包括根)所要删除的边的条数;void dfs(int s){int i,j,k,temp;for(i=0;i<=p;i++)dp[s][i]=0xffff;dp[s][1]=0;k=son[s];while(k){//对于每一,如果去掉k子树,则dp[s][i]=dp[s][i]+1;//否者为dp[s][i]=min(min(dp[s][j]+dp[k][i-j]))这里就是双重dp!!!dfs(k);for(i=p;i>=0;i--){temp=dp[s][i]+1;for(j=i;j>=0;j--){if(dp[k][i-j]+dp[s][j]<temp) temp=dp[k][i-j]+dp[s][j];}dp[s][i]=temp;}k=blo[k];//根据他来确定其他点父亲}}int solve(int root){dfs(root);int i,ans;ans=dp[root][p];for(i=1;i<=n;i++){if(dp[i][p]<ans)ans=dp[i][p]+1;//去掉子树与根i的边}return ans;}int main(){int i;while(scanf("%d%d",&n,&p)!=EOF){memset(hf,0,sizeof(hf));memset(blo,0,sizeof(blo));memset(son,0,sizeof(son));int a,b;for(i=0;i<n-1;i++){cin>>a>>b;blo[b]=son[a];son[a]=b;hf[b]=1;}int root;for(i=1;i<=n;i++) if(!hf[i]) root=i;//没有父节点的是根;cout<<solve(root)<<endl;}return 0;}