嘘~ 正在从服务器偷取页面 . . .

CF117C Cycle 题解


CF117C Cycle 题解

题目链接:CF117C Cycle

题意

一个 \(\texttt{tournament}\) 是一个没有自环的有向图,同时,每两个点之间有一条边连接。这就是说,对于两个点 \(u,v (u\neq v)\),有一条从 \(u\)\(v\) 的边或一条从 \(v\)\(u\) 的边。

给你一个 \(\texttt{tournament}\),请找出一个长度为 \(3\) 的环。

输入格式

第一行一个正整数 \(n(n \le 5\times 10^3)\)

接下来 \(n\) 行:一个 \(n \times n\) 的邻接矩阵 \(a\),由 01 组成。

\(a_{i,j}=1\),表示有一条路从 \(i\) 通往 \(j\)

数据保证 \(a_{i,i}=0\) 并且 \(a_{i,j} \neq a_{j,i}\)

输出格式

仅一行:任意一种解决方案;若没有,输出 -1

容易发现这个图就是有向完全图,也就是竞赛图。

根据竞赛题的性质可知,竞赛题如果存在环则一定存在三元环。

于是这道题就是一个简单的判环题,不过我们可以考虑用一种常数更小的判环方法来增加难度

考虑对于一个点 \(x\) ,我们能找到两个点 \(y,z\) 满足以下形式:

可以证明边 \((x,z)\) 是没有用的,即如果存在包含 \((x,z)\) 的三元环,那么一定存在一个不包含 \((x,z)\) 的三元环。

考虑枚举一个点 \(a\) ,其与 \(x,z\) 构成了一个三元环,如下图所示。

可以发现无论 \(y,a\) 连边的方向如何,均可产生一个不包含边 \((x,z)\) 的三元环。

则根据归纳法,对于每个节点 \(x\),我们只需要记录它的一个 \(\mathrm{to}(x)\)

接着我们枚举 \(x,y\) 并检查 \(x,\mathrm{to}(x),y\) 是否构成一个三元环即可。

时间复杂度 \(\mathcal{O}(n^2)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(5e3 + 15))

int n,to[N]; char g[N][N];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> (g[i] + 1);
    for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) {
        if(g[i][j] == '1' && (!to[i] || g[j][to[i]] == '1')) to[i] = j;
    }
    for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) {
        if(g[to[i]][j] == '1' && g[j][i] == '1')
            return cout << i << ' ' << to[i] << ' ' << j << '\n', 0;
    }
    cout << "-1" << '\n';
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/blog/stoorz/solution-cf117c


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录