1. 程式人生 > >Luogu 3698 [CQOI2017]小Q的棋盤

Luogu 3698 [CQOI2017]小Q的棋盤

alt std left cstring head 樹形 truct getchar() return

BZOJ 4813

雖然數據範圍很迷人,但是想樹形$dp$沒有前途。

先發現一個事情,就是我們可以先選擇一條鏈,最後要走到這一條鏈上不回來,走到鏈上的點每一個只需要一步,而如果要走這條鏈之外的點,一個點需要走兩步。

這條鏈怎麽選取?為了盡量減少步數,肯定是最長鏈。

現在有了一個顯然的事情,如果限制步數$stp$不比最長鏈長度$mx$大的話,那麽直接在最長鏈上走一走就好了,答案為$stp + 1$。

一棵樹最少需要$mx + 2 * (n - mx - 1) = 2n - mx - 2$步走完,如果$stp$不小於這個值,那麽一定能走完,答案為$n$。

剩下的情況只要先考慮走完最長鏈然後盡量分配步數到別的點上去就好了,答案為$mx + 1 + \left \lfloor \frac{stp - mx}{2} \right \rfloor$。

時間復雜度$O(n)$。

應該也有$dp$的辦法吧。

Code:

技術分享圖片
#include <cstdio>
#include <cstring>
using namespace std;

const int N = 105;

int n, stp, tot = 0, head[N], dep[N];

struct Edge {
    int to, nxt;
} e[N << 1];

inline void add(int from, int to) {
    e[++tot].to = to;
    e[tot].nxt 
= head[from]; head[from] = tot; } inline void read(int &X) { X = 0; char ch = 0; int op = 1; for(; ch > 9 || ch < 0; ch = getchar()) if(ch == -) op = -1; for(; ch >= 0 && ch <= 9; ch = getchar()) X = (X << 3) + (X << 1
) + ch - 48; X *= op; } inline void chkMax(int &x, int y) { if(y > x) x = y; } void dfs(int x, int fat, int depth) { dep[x] = depth; for(int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if(y == fat) continue; dfs(y, x, depth + 1); } } int main() { read(n), read(stp); for(int x, y, i = 1; i < n; i++) { read(x), read(y); ++x, ++y; add(x, y), add(y, x); } dfs(1, 0, 1); int mx = 0; for(int i = 1; i <= n; i++) chkMax(mx, dep[i] - 1); if(stp <= mx) return printf("%d\n", stp + 1), 0; if(stp >= 2 * n - mx - 2) return printf("%d\n", n), 0; printf("%d\n", mx + 1 + (stp - mx) / 2); return 0; }
View Code

Luogu 3698 [CQOI2017]小Q的棋盤