重建道路
——!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 }