AtCoder Grand Contest 001 C Shorten Diameter 樹的直徑
阿新 • • 發佈:2018-11-08
題意
- 給你一棵樹,每次可以刪除一個葉子節點,求最少需要多少次操作可以讓樹的直徑\(<=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; }