思路是參考別人而寫的!按照別人思路,敲了一遍代碼!
題意:給出n,p,一共有n個節點,要求最少減去最少的邊是多少,剩下p個節點
http://blog.csdn.net/libin56842/article/details/9834101 (思路轉自別人)
思路:典型的樹形DP,
dp[s][i]:記錄s結點,要得到一棵j個節點的子樹去掉的最少邊數
考慮其兒子k
1)如果不去掉k子樹,則
dp[s][i] = min(dp[s][j]+dp[k][i-j]) 0 <= j <= i
2)如果去掉k子樹,則
dp[s][i] = dp[s][i]+1
總的爲
dp[s][i] = min (min(dp[s][j]+dp[k][i-j]) , dp[s][i]+1 )
本人代碼:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int dp[155][155],n,m,num;
vector<int>id[155];
void dfs(int p,int t)
{
if(id[p].size()==1&&t!=-1) return ;
for(int i=0;i<id[p].size();i++)
{
int k=id[p][i];
if(k==t) continue;
dfs(k,p);
for(int j=m;j>=1;j--)
{
int sum=dp[p][j]+1;
for(int tt=1;tt<j;tt++)
sum=min(dp[p][tt]+dp[k][j-tt],sum);
dp[p][j]=sum;
//printf("%d %d %d\n",p,j,dp[p][j]);
}
}
}
void solve(int p,int t)
{
if(id[p].size()==1&&t!=-1)
{
if(t!=-1) num=min(dp[p][m]+1,num);
else num=min(dp[p][m],num);
return ;
}
for(int i=0;i<id[p].size();i++)
{
int k=id[p][i];
if(k==t) continue;
if(t!=-1) num=min(dp[p][m]+1,num);
else num=min(dp[p][m],num);
solve(k,p);
}
}
int main()
{
int i,j,a,b;
while(scanf("%d %d",&n,&m)!=EOF)
{
if(n==1)
{
printf("0\n");
continue;
}
for(i=0;i<=n;i++)
id[i].clear();
num=99999999;
for(i=1;i<n;i++)
{
scanf("%d %d",&a,&b);
id[a].push_back(b);
id[b].push_back(a);
}
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(j!=1) dp[i][j]=99999999;
else dp[i][1]=0;
}
}
dfs(1,-1);
solve(1,-1);
printf("%d\n",num);
}
return 0;
}