分析:
求最少删除多少边才能得到一颗含有P节点的子树。从根节点开始往下推能得出dp数组(见问题三)。题解:
1.用vector建树,存储:
for(int i=0;i<=n;i++)
vec[i].clear(); //每次先清空vector
for(int i=1;i<n;i++)
{
int a,b;
cin >> a >> b;
vec[a].push_back(b);
father[b]++; //记录每个节点的父节点个数,以便之后找出根节点
}
2.DFS搜索:
void DFS(int x)
{
for(int i = 0; i<=p; i++)
dp[x][i] = 10000000;//初始化
dp[x][1] = 0;//选一个节点的情况不需要删边,赋值为0.
for(int i=0;i<vec[x].size();i++)
{
int F = vec[x][i];
DFS(F);//搜索每一个子节点
for(int i = p;i>=1;i--)
{
int tem = dp[x][i]+1;//含有i个节点时,每次都不选子节点F的情况
for(int j=1; j<i;j++)
{
tem = min(tem,dp[F][i-j]+dp[x][j]);//与每次选了子节点F然后F含有j个子节点的情况比较
}
dp[x][i] = tem;
}
}
}
- AC代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <cmath>
#define N 222
using namespace std;
int dp[N][N];
vector <int> vec[N];
int n, p, root;
void DFS(int x)
{
for(int i = 0; i<=p; i++)
dp[x][i] = 10000000;
dp[x][1] = 0;
for(int i=0;i<vec[x].size();i++)
{
int F = vec[x][i];
DFS(F);
for(int i =p;i>=1;i--)
{
int tem = dp[x][i]+1;
for(int j=1; j<i;j++)
{
tem = min(tem,dp[F][i-j]+dp[x][j]);
}
dp[x][i] = tem;
}
}
}
int solve()
{
int ans;
DFS(root);
ans = dp[root][p];
for(int i = 1; i<=n; i++)
ans = min(ans, dp[i][p]+1);
return ans;
}
int father[N];
int main()
{
while(~scanf("%d%d",&n,&p))
{
memset(father, 0, sizeof(father));
for(int i=0; i<=n; i++)
{
vec[i].clear();
}
for(int i=1;i<n;i++)
{
int a,b;
cin >> a >> b;
vec[a].push_back(b);
father[b]++;
}
for(int i = 1; i<=n; i++)
{
if(!father[i])//找到根节点
{
root = i;
break;
}
}
printf("%d\n",solve());
}
}