1. 程式人生 > >AtCoder Grand Contest 001 C Shorten Diameter 樹的直徑

AtCoder Grand Contest 001 C Shorten Diameter 樹的直徑

題意

  • 給你一棵樹,每次可以刪除一個葉子節點,求最少需要多少次操作可以讓樹的直徑\(<=k,(n <= 2e3)\)

首先觀察資料範圍是可以接受\(O(n^2)\)的演算法的

我們考慮列舉每個點作為樹的根

統計這個點一定在直徑上時要刪多少點

如果\(k\)是偶數,那麼深度大於\(k/2\)的點就要被刪除

但是\(k\)是奇數還是不太好處理

我們可以列舉每條邊作為一定在直徑上的邊

從這條邊兩個端點分別找到深度大於\((k-1)/2\)的點刪除

這樣對所有答案取最小值即可

複雜度\(O(n^2)\)

Code

#include <bits/stdc++.h>

using namespace std;

#define For(i, a, b) for (register int i = (a), i##_end = b; i <= i##_end; ++ i) 
#define FOR(i, a, b) for (register int i = (a), i##_end = b; i >= i##_end; -- i) 
#define go(x, i) for (register int i = head[x]; i; i = nxt[i])
#define mem(a, b) memset(a, b, sizeof(a))
#define getc getchar_unlocked
#define putc putchar_unlocked
#define inf (0x3f3f3f3f)
#define INF (2e18)
#define pb push_back
#define mp make_pair
#define x first
#define y second
#define y1 igniubi

typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef long double ldb;
typedef double db;
typedef pair<int, int> PII;
typedef pair<ll, int> PLI;

inline void procStatus() {
    ifstream t("/proc/self/status");
    cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>());
}

const int N = 2e3 + 10;

PII E[N]; int n, k, ans = inf;

int to[N << 1], nxt[N << 1], head[N], e = 1;

inline void add(int x, int y) {
    to[++ e] = y; nxt[e] = head[x]; head[x] = e; 
}

namespace Sub1 {
    int dep[N], res, now[2];

    inline void dfs(int x, int dad, int typ) {
        go(x, i) if(to[i] ^ dad && to[i] ^ now[typ]) {
            dep[to[i]] = dep[x] + 1; 
            dfs(to[i], x, typ);
        }
        if (dep[x] > (k - 1) >> 1) ++ res;
    }

    inline void Solve() {
        For(i, 2, n) {
            mem(dep, res = 0);
            now[0] = E[i].x, now[1] = E[i].y;
            dfs(now[0], 0, 1), dfs(now[1], 0, 0);
            ans = min(ans, res);
        }
    }
}

namespace Sub2 {
    int dep[N], res;

    inline void dfs(int x, int dad) {
        go(x, i) if(to[i] ^ dad) {
            dep[to[i]] = dep[x] + 1; 
            dfs(to[i], x);
        }
        if (dep[x] > k >> 1) ++ res;
    }

    inline void Solve() {
        For(i, 1, n) {
            mem(dep, res = 0), dfs(i, 0);
            ans = min(ans, res);
        }
    }
}

int main() {
    //freopen("AT1981.in", "r", stdin);
    //freopen("AT1981.out", "w", stdout);

    int x, y;

    scanf("%d%d", &n, &k);
    For(i, 2, n) {
        scanf("%d%d", &x, &y);
        add(x, y), add(y, x);
        E[i] = mp(x, y);
    }

    if (k & 1) Sub1::Solve();
    else Sub2::Solve();

    printf("%d\n", ans);

    return 0;
}