P1272 重建道路

原题链接

考察:树形dp

推dp转移方程的时候,总是忘记f数组原来定义的含义...初始化也可以帮助推出dp数组.

思路:

        f[u][j] 表示以u为根的子树中,保留j个点最少的剪枝数.初始化f[u][1] = son[u].这样初始化一开始点都是独立的,通过下面的转移方程将它们连起来.

        那么dp转移方程 f[u][j] = min(f[u][j-k]+f[v][k]-1,f[u][j]).为什么-1呢当j = 2时,f[u][2] = f[u][1]+f[v][1] f[u][1]被初始化为全部的子节点数,我们还要将u-v的边减去.

        最后的ans是枚举子树根节点,如果当前点是1 ans = min(ans,f[u][p]) 如果不是 ans = min(ans,f[u][p]+1).

 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 const int N = 160,INF = 0x3f3f3f3f;
 5 int n,p,idx,h[N],son[N],f[N][N],ans = INF;
 6 struct Road{
 7     int fr,to,ne;
 8 }road[N];
 9 void add(int a,int b)
10 {
11     road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++;
12 }
13 void dfs(int u) 
14 {
15     f[u][1] = son[u];
16     for(int i=h[u];i!=-1;i=road[i].ne)
17     {
18         int v = road[i].to;
19         dfs(v);
20         for(int j=p;j>=1;j--)
21           for(int k=0;k<j;k++)
22             f[u][j] = min(f[v][k]+f[u][j-k]-1,f[u][j]);
23     }
24     if(u!=1) ans = min(ans,f[u][p]+1); 
25     else ans = min(ans,f[u][p]);
26 }
27 int main()
28 {
29     scanf("%d%d",&n,&p);
30     memset(h,-1,sizeof h);
31     for(int i=1;i<n;i++)
32     {
33         int a,b; scanf("%d%d",&a,&b);
34         add(a,b);
35         son[a]++;
36     }
37     memset(f,0x3f,sizeof f);
38     dfs(1);
39     printf("%d\n",ans);
40     return 0;
41 }

 

posted @ 2021-04-07 12:31  acmloser  阅读(65)  评论(0编辑  收藏  举报