1、http://poj.org/problem?id=1947
2、题目大意:
已知一棵树有n个结点,现在要删除部分边,使得有一棵独立的子树上的结点个数为p个,求满足条件下,最少删除几条边
分析:
这是一道树形DP,对于第k条边来说要么删除要么不删除
dp[i][j]表示以i为根的树有j个结点的最小代价(最少删除的边数),
dp[u][j]=max(dp[u][j]+1,dp[u][j-k]+dp[v][k])
要是删除第k条边那么dp[u][j]=dp[u][j]+1,不删除第K条边就等于dp[u][j-k]+dp[v][k]
3、AC代码:
#include<stdio.h>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 155
#define INF 0x7ffffff
vector<int> adj[N];
int in[N],m,n;
int dp[N][N];
int tmp;
void dfs(int u)
{
for(int i=0; i<=n; i++)
dp[u][i]=INF;
dp[u][1]=0;
for(int i=0; i<adj[u].size(); i++)
{
int v=adj[u][i];
dfs(v);
for(int j=m; j>=0; j--)
{
tmp=dp[u][j]+1;
for(int k=0; k<=j; k++)
{
tmp=min(tmp,dp[u][j-k]+dp[v][k]);
}
dp[u][j]=tmp;
}
}
}
int main()
{
int a,b,s;
scanf("%d%d",&n,&m);
memset(in,0,sizeof(in));
for(int i=1; i<n; i++)
{
scanf("%d%d",&a,&b);
in[b]++;
adj[a].push_back(b);
}
for(int i=1; i<=n; i++)
{
if(in[i]==0)
{
s=i;
break;
}
}
dfs(s);
int ans=dp[s][m];
for(int i=1; i<=n; i++)
{
if(dp[i][m]<ans)
ans=dp[i][m]+1;
}
printf("%d\n",ans);
return 0;
}
/*
11 6
1 2
1 3
1 4
1 5
2 6
2 7
2 8
4 9
4 10
4 11
*/