Codeforces 1325F DFS 树

164 篇文章 0 订阅
题意

传送门 Codeforces 1325F Ehab’s Last Theorem

题解

s q = ⌈ n ⌉ sq = \lceil \sqrt{n}\rceil sq=n ,构造 D F S DFS DFS 树,若存在返祖边包含至少 s q sq sq 个节点,则找到了一个满足要求的简单环。

否则,任一节点的返祖边及其与父节点的连边的数量至多为 s q − 2 sq-2 sq2;故将任一节点包含于独立集,至多需要排除 s q − 2 sq-2 sq2 个节点。则自底向上不断向独立集添加点,至少可以包含 s q sq sq 个点(也可以通过图染色进行构造)。总时间复杂度 O ( n + m ) O(n+m) O(n+m)

独立集点数的下界证明如下:
s q − 1 < n ≤ s q   ⇒ n s q − 1 > n n = n sq-1<\sqrt{n}\leq sq\ \Rightarrow \frac{n}{sq-1}>\frac{n}{\sqrt{n}}=\sqrt{n} sq1<n sq sq1n>n n=n
根据顶函数的单调非减性质,得到 ⌈ n s q − 1 ⌉ ≥ ⌈ n ⌉ \lceil\frac{n}{sq-1}\rceil\geq \lceil \sqrt{n}\rceil sq1nn

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l, _ = r; i < _; ++i)
#define pb push_back
typedef long long ll;
const int MAXN = 1E5 + 5;
int N, M, dep[MAXN], par[MAXN], sz;
vector<int> G[MAXN], rec;
bool found, ban[MAXN];

void dfs(int u, int p, int d)
{
    dep[u] = d, par[u] = p;
    for (auto &v : G[u])
    {
        if (dep[v] == -1)
        {
            dfs(v, u, d + 1);
        }
        else if (v != p)
        {
            if (found)
                continue;
            if (dep[u] - dep[v] + 1 >= sz)
            {
                found = 1;
                vector<int> res;
                res.pb(v);
                int w = u;
                while (w != v)
                    res.pb(w), w = par[w];
                cout << "2\n";
                cout << (int)res.size() << '\n';
                for (auto &v : res)
                    cout << v + 1 << ' ';
                cout << '\n';
            }
        }
    }
    if (!ban[u])
    {
        if ((int)rec.size() < sz)
            rec.pb(u);
        for (auto &v : G[u])
            ban[v] = 1;
    }
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> N >> M;
    int lb = 0, ub = 1000;
    while (ub - lb > 1)
    {
        int mid = (lb + ub) >> 1;
        if (mid * mid < N)
            lb = mid;
        else
            ub = mid;
    }
    sz = ub;
    
    rep(i, 0, M)
    {
        int u, v;
        cin >> u >> v;
        --u, --v;
        G[u].pb(v), G[v].pb(u);
    }
    memset(dep, -1, sizeof(dep));
    dfs(0, -1, 0);
    if (!found)
    {
        cout << "1\n";
        for (auto &v : rec)
            cout << v + 1 << ' ';
        cout << '\n';
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值