poj 1947 Rebuilding Roads

题意:给定一棵树,求切出有n个结点的子树至少要切几条边。

解法:dp[i][j]记录使得以i为根的子树有j个结点最少要切几条边

  dp[i][j]=min(dp[i][j],dp[i][j-k]+dp[son[i]][k])

  最后统计答案时要注意,如果不是根节点还要+1...切掉这个节点与其父亲之间的边

 1 #include<iostream>
 2 #include<vector>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define N 200
 6 using namespace std;
 7 const int inf=(1<<30);
 8 vector<int>V[N];
 9 int dp[N][N];
10 int cnt[N];
11 int p;
12 void cal(int n){
13     if(V[n].size()==0){
14         cnt[n]=1;
15         return ;
16     }
17     cnt[n]=0;
18     for(int i=0;i<V[n].size();i++){
19         cal(V[n][i]);
20         cnt[n]+=cnt[V[n][i]];
21     }
22 }
23 void dfs(int n){
24     for(int i=0;i<V[n].size();i++)
25         dfs(V[n][i]);
26     dp[n][1]=V[n].size();
27     for(int i=0;i<V[n].size();i++){
28         int son=V[n][i];
29         for(int j=p;j>=1;j--)
30             for(int k=1;k<j;k++)
31                 if(dp[n][j-k]<inf&&dp[son][k]<inf)
32                     dp[n][j]=min(dp[n][j],dp[n][j-k]+dp[son][k]-1);
33     }
34 }
35 int main(){
36     int n;
37     while(cin>>n>>p){
38         for(int i=0;i<N;i++)V[i].clear();
39         for(int i=0;i<N;i++)
40             for(int j=0;j<N;j++)
41                 dp[i][j]=inf;
42         for(int i=1;i<n;i++){
43             int a,b;
44             cin>>a>>b;
45             V[a].push_back(b);
46         }
47         cal(1);
48         dfs(1);
49         int ans=dp[1][p];
50         for(int i=2;i<=n;i++)
51             ans=min(ans,dp[i][p]+1);
52         cout<<ans<<endl;
53     }
54     return 0;
55 }

 

posted @ 2012-10-31 19:48  silver__bullet  阅读(186)  评论(0编辑  收藏  举报