Codeforces Global Round 8 E. Ski Accidents

Posted kanoon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Global Round 8 E. Ski Accidents相关的知识,希望对你有一定的参考价值。

题目链接: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();
}

 

以上是关于Codeforces Global Round 8 E. Ski Accidents的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Global Round 8 A. C+=(贪心)

Codeforces Global Round 8 E. Ski Accidents

Codeforces Global Round 8 E - Ski Accidents 拓扑

Codeforces Global Round 8 D. AND, OR and square sum(位运算)

Codeforces Global Round 1

Codeforces Global Round 8 D - AND, OR and square sum 尽量往大的数字上移动