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 }