/*
* Cpp0.cpp
*
* Created on: 2014年7月8日
* Author: MIAO
*/
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
using namespace std;
vector<int> V[155];
int dp[155][155];
int n,p;
const int inf=0xffffff;
void dfs(int root)
{
int i,j,k;
//先计算完毕所有子树
for (i=0;i<(int)V[root].size();i++)
dfs(V[root][i]);
dp[root][1]=0;
//类似背包问题的DP,对于第i个子树,拿或者不拿两种情况
for (i=0;i<(int)V[root].size();i++)
{
int son=V[root][i];
//维护dp[root][1..p]
for (j=p;j>=1;j--)
{
int temp=dp[root][j]+1;//如果不拿第i个子树,则切断这个子树,次数+1
//如果拿第i个子树,需枚举第i个子树中要取多少个点,假设第i个子树取k个,从上一个状态(第1..i-1个子树)取j-k个,找出最小值
for (k=1;k<j;k++)
temp=min(dp[root][j-k]+dp[son][k],temp);
dp[root][j]=temp;
}
}
}
void init()
{
for (int i=0;i<=n;i++)
for (int j=0;j<=p;j++)
dp[i][j]=inf;
}
int main()
{
int i;
int degree[155]={0};//入度
scanf("%d%d",&n,&p);
init();
for (i=0;i<n-1;i++)
{
int a,b;
scanf("%d%d",&a,&b);
V[a].push_back(b);
degree[b]++;
}
//找根
for (i=1;i<=n;i++)
if (!degree[i])
break;
dfs(i);
//以每个节点为根,找出最小值
int ans=dp[i][p];//原来的根,不用+1
//其它节点要成为根要切断其和父节点的边
for (i=1;i<=n;i++)
if (dp[i][p]+1<ans)
ans=dp[i][p]+1;
printf("%d\n",ans);
}
顺推要增加一维:
/*
* Cpp0.cpp
*
* Created on: 2014年7月8日
* Author: MIAO
*/
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
using namespace std;
vector<int> V[155];
int dp[155][155][155];
int n,p;
const int inf=0xffffff;
void dfs(int root)
{
int i,j,k;
//先计算完毕所有子树
for (i=0;i<(int)V[root].size();i++)
dfs(V[root][i]);
dp[0][root][1]=0;
//类似背包问题的DP,对于第i个子树,拿或者不拿两种情况
for (i=1;i<=(int)V[root].size();i++)
{
int son=V[root][i-1];
int son_size=V[son].size();
//维护dp[root][1..p]
for (j=1;j<=p;j++)
{
int temp=dp[i-1][root][j]+1;//如果不拿第i个子树,则切断这个子树,次数+1
//如果拿第i个子树,需枚举第i个子树中要取多少个点,假设第i个子树取k个,从上一个状态(第1..i-1个子树)取j-k个,找出最小值
for (k=1;k<j;k++)
temp=min(dp[i-1][root][j-k]+dp[son_size][son][k],temp);
dp[i][root][j]=temp;
}
}
}
void init()
{
for (int k=0;k<=n;k++)
for (int i=0;i<=n;i++)
for (int j=0;j<=p;j++)
dp[k][i][j]=inf;
}
int main()
{
int i;
int degree[155]={0};//入度
scanf("%d%d",&n,&p);
init();
for (i=0;i<n-1;i++)
{
int a,b;
scanf("%d%d",&a,&b);
V[a].push_back(b);
degree[b]++;
}
//找根
for (i=1;i<=n;i++)
if (!degree[i])
break;
dfs(i);
//以每个节点为根,找出最小值
int ans=dp[V[i].size()][i][p];//原来的根,不用+1
//其它节点要成为根要切断其和父节点的边
for (i=1;i<=n;i++)
if (dp[V[i].size()][i][p]+1<ans)
ans=dp[V[i].size()][i][p]+1;
printf("%d\n",ans);
}