[luogu]P1272 重建道路[树形DP]

[luogu]P1272

重建道路

——!x^n+y^n=z^n

题目描述

一场可怕的地震后,人们用N个牲口棚(1≤N≤150,编号1..N)重建了农夫John的牧场。由于人们没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是惟一的。因此,牧场运输系统可以被构建成一棵树。John想要知道另一次地震会造成多严重的破坏。有些道路一旦被毁坏,就会使一棵含有P(1≤P≤N)个牲口棚的子树和剩余的牲口棚分离,John想知道这些道路的最小数目。

输入输出格式

输入格式:

第1行:2个整数,N和P

第2..N行:每行2个整数I和J,表示节点I是节点J的父节点。

输出格式:

单独一行,包含一旦被破坏将分离出恰含P个节点的子树的道路的最小数目。

输入输出样例

输入样例1#:

11 6

1 2

1 3

1 4

1 5

2 6

2 7

2 8

4 9

4 10

4 11

输出样例1#:

2

说明

【样例解释】

如果道路1-4和1-5被破坏,含有节点(1,2,3,6,7,8)的子树将被分离出来


很容易想到树形背包,用f[i][j]表示以i为根,删得只剩下j个点的最少删除。

f[i][j]=Min{f[v][k]+f[i][j-k]-2}(v为i的孩子)[(v,i)应该留下,可两个决策都减了,要-2]。

初始化:f[i][1]=边数,f[root][1]=边数-1。

一开始理解错题意,以为root一定要保留,结果就gg了,呵呵。

代码:

 1 //2017.10.29
 2 //DP
 3 #include<iostream>
 4 #include<cstdio>
 5 #include<cstring>
 6 using namespace std;
 7 inline int read();
 8 int Min(int x,int y){return x<y?x:y;}
 9 namespace lys{
10     const int N = 150 + 7 ;
11     struct edge{
12         int to;
13         int next;
14     }e[N*3];
15     int dp[N][N],pre[N],count[N],fa[N];
16     int n,p,cnt,ans;
17     void add(int x,int y){e[++cnt].to=y;e[cnt].next=pre[x];pre[x]=cnt;}
18     void dfs(int node){
19         int i,j,k,v;
20         dp[node][1]=count[node]+(fa[node]!=0);
21         for(i=pre[node];~i;i=e[i].next){
22             v=e[i].to;
23             dfs(v);
24             for(j=p;j>=2;j--)
25                 for(k=1;k<j;k++)
26                     dp[node][j]=Min(dp[node][j],dp[v][k]+dp[node][j-k]-2);
27         }
28         ans=Min(dp[node][p],ans);
29     }
30     int main(){
31         int i,u,v;
32         n=read(); p=read();
33         memset(pre,-1,sizeof pre);
34         memset(dp,0x7,sizeof dp);
35         ans=dp[1][1];
36         for(i=1;i<n;i++){
37             u=read(); v=read();
38             add(u,v);
39             count[u]++;
40             fa[v]=u;
41         }
42         for(i=1;i<=n;i++) if(!fa[i]){dfs(i);break;}
43         printf("%d
",ans);
44         return 0;
45     }
46 }
47 int main(){
48     lys::main();
49     return 0;
50 }
51 inline int read(){
52     int kk=0,ff=1;
53     char c=getchar();
54     while(c<'0'||c>'9'){
55         if(c=='-') ff=-1;
56         c=getchar();
57     }
58     while(c>='0'&&c<='9') kk=kk*10+c-'0',c=getchar();
59     return kk*ff;
60 }
原文地址:https://www.cnblogs.com/_inx/p/7751263.html