题目链接:https://codeforces.com/contest/1368/problem/E
题意
给出一个 $n$ 点 $m$ 边的有向图,每条边由编号较小的点通向编号较大的点,每个点的出度不大于 $2$,删掉一些点,使得图中不存在长度大于等于 $2$ 的路径。(最多删掉 $frac{4}{7}n$ 个点)
题解
删除所有拓扑排序中深度为 $3$ 的倍数的顶点,由于每次删掉了一层,所以把所有点深度置为 $1$,只删除深度为 $3$ 的顶点即可。
证明
删除点占比最大的情况是该有向图为满二叉树且深度为 $3$ 的倍数,要删除的点即深度为 $3$ 的倍数每层结点,删除结点的个数与满二叉树结点的总个数之比为:
egin{equation} frac{2^2 + 2^5 + dots + 2^{3n - 1}}{2^0 + 2^1 + 2^2 + dots + 2^{3n - 1}} end{equation}
分子分母等比数列求和得:
egin{equation} frac{ frac{4(1 - 8^n)}{1 - 8} }{ frac{(1 - 2^{3n})}{1 - 2} } end{equation}
化简得:
egin{equation} frac{4}{7} end{equation}
即最多删除 $frac{4}{7}n$ 个结点。
代码
#include <bits/stdc++.h> using namespace std; void solve() { int n, m; cin >> n >> m; vector<int> G[n + 1]; for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; if (u == v) continue; G[u].push_back(v); } vector<int> ans; vector<int> dis(n + 1, 1); for (int u = 1; u <= n; u++) { if (dis[u] == 3) { ans.push_back(u); continue; } for (auto v : G[u]) dis[v] = max(dis[v], dis[u] + 1); } cout << ans.size() << " "; for (auto i : ans) cout << i << " "[i == ans.back()]; } int main() { int t; cin >> t; while (t--) solve(); }