zoukankan      html  css  js  c++  java
  • [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 }
  • 相关阅读:
    [APIO2016]划艇
    C# 循环的判断会进来几次
    C# 性能分析 反射 VS 配置文件 VS 预编译
    C# 性能分析 反射 VS 配置文件 VS 预编译
    AutoHotKey 用打码的快捷键
    AutoHotKey 用打码的快捷键
    C# 通过编程的方法在桌面创建回收站快捷方式
    C# 通过编程的方法在桌面创建回收站快捷方式
    C# 条件编译
    C# 条件编译
  • 原文地址:https://www.cnblogs.com/skylee03/p/7685516.html
Copyright © 2011-2022 走看看