Codeforces 117C Cycle 题解 [ 蓝 ] [ 竞赛图 ] [ Tarjan ] [ 构造 ]

Cycle

困难图论题。

结论 \(1\):如果一张竞赛图存在环,那么一定存在三元环。

证明:
取环上连续的三个点 \(a\to b\to c\),根据竞赛图的性质,\(a, c\) 之间必然存在一条边:

  • \(a\to c\),那么我们可以把 \(a\to b \to c\) 直接替换为 \(a \to c\),使得环的长度减小 \(1\)
  • 否则满足 \(a\leftarrow c\),那么说明我们直接找到了三元环。
    原命题得证。

于是直接使用 Tarjan 找到一个环,模拟上述过程即可。时间复杂度 \(O(n^2)\)

除此之外,还有一种写起来更简单做法:

结论 \(2\):若有一个子图满足 \(a\to b, a \to c, b \to c\) 的结构,那么我们一定能把 \(a\to c\) 这条边删去使得三元环存在性不变。

证明:
只考虑经过删去边的环 \(x\to a\to c\to x\)
根据三元环的性质,\(x, b\) 之间必然存在一条边:

  • \(b\to x\),那么 \(x\to a \to b\to x\) 的一个环一定存在。
  • \(x\to b\),那么 \(x\to b \to c\to x\) 的一个环一定存在。
    原命题得证。

因此在执行删边后,最后所有点都只有一个出边,我们只需要用这 \(O(n)\) 条出边判断三元环即可。

#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi = pair<int, int>;
const int N = 5005;
int n, to[N];
bitset<N> g[N];
int main()
{
    //freopen("sample.in", "r", stdin);
    //freopen("sample.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            char c;
            cin >> c;
            g[i][j] = c - '0';
        }
    }
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            if(g[i][j] && (!to[i] || g[j][to[i]]))
                to[i] = j;
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            if(g[j][i] && g[to[i]][j])
            {
                cout << i << " " << to[i] << " " << j;
                return 0;
            }
        }
    }
    cout << "-1";
    return 0;
}
posted @ 2025-11-26 14:39  KS_Fszha  阅读(6)  评论(0)    收藏  举报