[Codeforces440D]Berland Federalization

Problem

给你一棵树,最少删掉哪些边,能使得余下的至少有1个大小刚好为k的残树。
1 ≤ k ≤ n ≤ 400

Solution

用f[i][j]表示以i为根有j个节点的最少删边数量
因为此题要输出删除的边
v[i][j]表示以i为根删掉j个节点需要删去的边对应的(点u,该u点还需要删去的边数量)

Notice

因为要输出方案,所以比较复杂

Code

#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define sqz main
#define ll long long
#define reg register int
#define rep(i, a, b) for (reg i = a; i <= b; i++)
#define per(i, a, b) for (reg i = a; i >= b; i--)
#define travel(i, u) for (reg i = head[u]; i; i = edge[i].next)
typedef pair<int, int> Node;
const int INF = 1e9, N = 400;
const double eps = 1e-6, phi = acos(-1.0);
ll mod(ll a, ll b) {if (a >= b || a < 0) a %= b; if (a < 0) a += b; return a;}
ll read(){ ll x = 0; int zf = 1; char ch; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if (ch == '-') zf = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;}
void write(ll y) { if (y < 0) putchar('-'), y = -y; if (y > 9) write(y / 10); putchar(y % 10 + '0');}
struct node
{
    int vet, next;
}edge[N + 5];
int head[N + 5], num = 0, f[N + 5][N + 5], Flag[N + 5], fa[N + 5], n, k;
vector<Node> v[N + 5][N + 5];
void add(int u, int v)
{
    edge[++num].vet = v;
    edge[num].next = head[u];
    head[u] = num;
}
void dfs(int u)
{
    rep(i, 0, k) f[u][i] = INF;
    f[u][1] = 0;
    travel(i, u)
    {
        int vv = edge[i].vet;
        if (vv == fa[u]) continue;
        fa[vv] = u;
        dfs(vv);
        per(j, k, 0)
        {
            f[u][j]++;
            rep(t, 0, j)
                if (f[u][j - t] + f[vv][t] < f[u][j])
                {
                    f[u][j] = f[u][j - t] + f[vv][t];
                    v[u][j].clear();
                    v[u][j].assign(v[u][j - t].begin(), v[u][j - t].end());
                    v[u][j].push_back(make_pair(vv, t));
                }
        }
    }
}
void Out(int u, int now)
{
    Flag[u] = 1;
    for (auto i : v[u][now]) Out(i.first, i.second);
    travel(i, u)
        if (!Flag[edge[i].vet]) printf("%d ", (i + 1) / 2);
}
int sqz()
{
    n = read(), k = read();
    rep(i, 1, n) head[i] = 0;
    rep(i, 1, n - 1)
    {
        int u = read(), v = read();
        add(u, v), add(v, u);
    }
    dfs(1);
    int ans = f[1][k], root = 1;
    rep(i, 2, n)
        if (f[i][k] + 1 < ans) ans = f[i][k] + 1, root = i;
    printf("%d\n", ans) ;
    if (ans) Out(root, k);
    puts("");
    return 0;
}

转载于:https://www.cnblogs.com/WizardCowboy/p/7689868.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值