By askhelper, 6 months ago, , Hello, all! I am thinking about the following problem:

Given a tree with N vertices and some constant D. You are to find maximum number of vertices you can color if distance between any two colored vertices should be at least D.

How to solve this problem better than $O(N^2)$? I think for $O(N^2)$ we can use greedy approach; choose the farthest available vertex from the root.

Any helps are appreciated.  Comments (3)
 » 6 months ago, # | ← Rev. 3 →   I don't see how your greedy approach is working. I have dp solution: root tree in 1 and calculate dp[i][j] for every vertex i and every deep 0<=j<=D recursively, where dp[i][j] is answer for subtree of i where the closest colored vertex is on deep j. Dp equations aren't really hard in that case, something like dp[i][j]=max(dp[u][j-1]+sum_on_children(dp[v][D-j])-dp[u][D-j]) and dp[i]=sum(dp[u][D-1])+1. For every node we need O(D*deg_of_node) operations so it work in O(D*sum(deg))=O(N*D) and answer is max(dp[j]). Sorry for bad English. EDIT: for j>=D/2 dp[i][j] is just sum(dp[u][j-1])
•  » » $d \leq n$, so it is same as $O(n^2)$ when d is big enough.
 » Very nice problem. Your greedy is correct and that can be used for $O(n\cdot\sqrt{n})$ solution. Firstly, let's think about "brute-force" solution. Sort all vertices for its depth from root in descending order. Then iterate these vertices and if current vertex is available then increment the answer and start dfs from that vertex. dfs may go at most $O(n)$ vertices and we do dfs for each "answer vertex". Notice that answer can be at most $O(\frac{n}{d})$. So, overall complexity is $O(\frac{n^2}{d})$.Now, the tricky part. If we use two dimensional used array such that used[v][d] means we are currently in the vertex v and we will go d more vertices; then we can stop if used[v][d] is already true in the dfs. So, the complexity becomes $O(n\cdot d)$.Finally, we combine above solutions. If $d \leq \sqrt{n}$ then do the second, otherwise do the first one. It can be coded neatly with only one dfs. Code#include #define endl '\n' using namespace std; const int INF = 1000000000; const int N = 200005; const int B = 450; int n, d; vector g[N]; int used[N], lvl[N]; int used2[B][N]; void dfs(int v, int ds, int p = -1) { if (ds == 0) return; used[v] = 1; if (d < B) used2[ds][v] = 1; for (int i : g[v]) { if ((d < B && used2[ds - 1][i] == 1) || i == p) continue; dfs(i, ds - 1, v); } } int main() { ios_base :: sync_with_stdio(0); cin.tie(0), cout.tie(0); cin >> n >> d; vector > nds; nds.push_back({0, 0}); for (int i = 1; i < n; i++) { int x; cin >> x; g[i].push_back(x), g[x].push_back(i); lvl[i] = lvl[x] + 1; nds.push_back({lvl[i], i}); } sort(nds.rbegin(), nds.rend()); int res = 0; for (auto i : nds) { if (used[i.second] == 1) continue; res++; dfs(i.second, d); } cout << res << endl; return 0; }