POJ 1947 Rebuilding Roads

Rebuilding Roads
 

Description

The cows have reconstructed Farmer John's farm, with its N barns (1 <= N <= 150, number 1..N) after the terrible earthquake last May. The cows didn't have time to rebuild any extra roads, so now there is exactly one way to get from any given barn to any other barn. Thus, the farm transportation system can be represented as a tree. 

Farmer John wants to know how much damage another earthquake could do. He wants to know the minimum number of roads whose destruction would isolate a subtree of exactly P (1 <= P <= N) barns from the rest of the barns.

Input

* Line 1: Two integers, N and P 

* Lines 2..N: N-1 lines, each with two integers I and J. Node I is node J's parent in the tree of roads. 

Output

A single line containing the integer that is the minimum number of roads that need to be destroyed for a subtree of P nodes to be isolated. 

Sample Input

11 6
1 2
1 3
1 4
1 5
2 6
2 7
2 8
4 9
4 10
4 11

Sample Output

2

Hint

[A subtree with nodes (1, 2, 3, 6, 7, 8) will become isolated if roads 1-4 and 1-5 are destroyed.] 
题意:
有n个点组成一棵树,问至少要删除多少条边才能获得一棵有p个结点的子树?
一道转移比较有意思的树形dp题。
树上的状态应该比较明确。dp[i][j]表示以i为根有j个节点的子树。
转移怎么办?
把它的子树编成1,2..x。
每个子树取几个或不取达到j-1(自己有1个节点)。
我们好像又能搞出一个dp,
dp_[i][j]表示前i个子树取了j个节点。
有dp_[i][j]=min{dp_[i-1][k]+dp[i][j-k]-2};(添加一条边要减2);
还有dp_[i][j]=min{dp[i-1][k]};
倒着枚举j。
可以变成:
dp_[j]=min(dp_[j],dp_[j-k]+dp[i][j-k]-2);
直接放在原数组上做:
        for (int j=m;j>1;j--){
            for (int k=1;k<j;k++){
                dp[u][j]=min(dp[u][j],dp[u][k]+dp[v[i]][j-k]-2);
            }
        }

代码:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=1000000007;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; }
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
32 ll read(){ ll ans=0; char last=' ',ch=getchar();
33 while(ch<'0' || ch>'9')last=ch,ch=getchar();
34 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
35 if(last=='-')ans=-ans; return ans;
36 }
37 const int M=1000,N=200,inf=1e09;
38 int n,m;
39 int v[M],Next[M],head[N],e,dp[N][N],du[N];
40 void add(int x,int y){ v[++e]=y; Next[e]=head[x]; head[x]=e;}
41 void dfs(int u,int fa){
42     for (int i=head[u];i;i=Next[i])
43     if (v[i]!=fa){
44         dfs(v[i],u);
45         for (int j=m;j>1;j--){
46             for (int k=1;k<j;k++){
47                 dp[u][j]=min(dp[u][j],dp[u][k]+dp[v[i]][j-k]-2);
48             }
49         }
50     }
51 }
52 int main(){
53     n=read(),m=read();
54     for (int i=1;i<n;i++) {
55         int a=read(),b=read();
56         add(a,b); add(b,a);
57         du[a]++; du[b]++;
58     }
59     for (int i=1;i<=n;i++){
60         dp[i][1]=du[i];
61         for (int j=2;j<=m;j++) 
62             dp[i][j]=inf;
63     }
64     dfs(1,0);
65     int ans=inf;
66     for (int i=1;i<=n;i++)
67         ans=min(ans,dp[i][m]);
68     printf("%d",ans);
69     return 0;
70 } 
View Code
原文地址:https://www.cnblogs.com/SXia/p/7641038.html