[CodeForces-440D]Berland Federalization

题目大意:
  给你一棵树,你可以删掉一些边,使得分除去的子树中至少有一棵大小为k。
  问最少删去多少边,以及删边的具体方案。

思路:
  树形DP。
  f[i][j]表示以i为根,子树中去掉j个点最少要删边的数量;
  v[i][j]表示其具体方案。
  然后对每个点跑一下背包。
  状态转移方程f[x][k+j]=min{f[x][k]+f[y][j]|y为x子结点}。
  注意y的不同状态不能同时对x的同一个状态产生影响,所以转移的时候必须把数组复制一遍,将原数组和转移过后的数组隔离开来。
  v的转移只需要把v[x][k]和v[y][j]并起来就OK了。
  最后答案枚举每个结点的f[node][size[node]-k],如果不是一开始假定的根结点1,我们要将其与主树连接的边算入答案。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<vector>
 4 #include<cstring>
 5 inline int getint() {
 6     register char ch;
 7     while(!isdigit(ch=getchar()));
 8     register int x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 const int inf=0x7fffffff;
13 const int N=401;
14 struct Edge {
15     int to,id;
16 };
17 std::vector<Edge> e[N];
18 inline void add_edge(const int &u,const int &v,const int &i) {
19     e[u].push_back((Edge){v,i});
20     e[v].push_back((Edge){u,i});
21 }
22 int size[N],f[N][N];
23 int t[N],pre[N];
24 std::vector<int> v[N][N];
25 void dfs(const int &x,const int &par) {
26     size[x]=1;
27     int eid;
28     for(unsigned i=0;i<e[x].size();i++) {
29         const int &y=e[x][i].to;
30         if(y==par) {
31             eid=e[x][i].id;
32             continue;
33         }
34         pre[y]=e[x][i].id;
35         dfs(y,x);
36         size[x]+=size[y];
37     }
38     f[x][0]=0;
39     f[x][size[x]]=1;
40     v[x][size[x]].push_back(eid);
41     std::fill(&f[x][1],&f[x][size[x]],inf);
42     for(unsigned i=0;i<e[x].size();i++) {
43         const int &y=e[x][i].to;
44         eid=e[x][i].id;
45         if(y==par) continue;
46         memcpy(t,f[x],sizeof t);
47         for(int j=0;j<=size[y];j++) {
48             for(int k=0;k<size[x]-j;k++) {
49                 if(f[x][k]==inf) continue;
50                 if(f[x][k]+f[y][j]<t[k+j]) {
51                     t[k+j]=f[x][k]+f[y][j];
52                     v[x][k+j]=v[x][k];
53                     v[x][k+j].insert(v[x][k+j].end(),v[y][j].begin(),v[y][j].end());
54                 }
55             }
56         }
57         memcpy(f[x],t,sizeof t);
58     }
59 }
60 int main() {
61     int n=getint(),k=getint();
62     for(register int i=1;i<n;i++) {
63         add_edge(getint(),getint(),i);
64     }
65     dfs(1,0);
66     int ans=f[1][size[1]-k],node=1;
67     for(register int root=2;root<=n;root++) {
68         if(size[root]<k) continue;
69         f[root][size[root]-k]++;
70         v[root][size[root]-k].push_back(pre[root]);
71         if(f[root][size[root]-k]<ans) {
72             ans=f[root][size[root]-k];
73             node=root;
74         }
75     }
76     printf("%d
",ans);
77     for(register unsigned i=0;i<v[node][size[node]-k].size();i++) {
78         printf("%d ",v[node][size[node]-k][i]);
79     }
80     return 0;
81 }
原文地址:https://www.cnblogs.com/skylee03/p/7685516.html