标签:pac 过程 https tchar row lang == ble continue
给出一个竞赛图(每两个点之间都有一条有向边),试找出图中的一个三元环,若不存在输出\(-1\)。\((n\le5000)\)
注意到竞赛图如果有一个大环,那么中间一定会有三元环。这是比较好证明的。(下面是蒯的)
假设一个竞赛图存在一个\(N\)元环(大于三元),环上有连续三点\(A , B , C\)( 存在有向边\(AB , BC\))
根据竞赛图的定义,一定存在有向边\(CA\)或\(AC\)中的一者。
情况\(1\):若存在\(CA\),则\(A , B , C\)构成三元环;
情况\(2\):若存在\(AC\) ,不考虑\(B\)点,剩下的点构成一个\((N-1)\)元环。显然,如果一直不存在情况\(1\)的话,最终也会形成一个三元环。
这个在纸上自己模拟一下就好了。
所以我们用\(Tarjan\)找出图中每一个强连通分量。注意到对于中间的某个点对\((A,B)\),假设它们在原图上的边是\(A\rightarrow{B}\),又因为\(B\)也可以到\(A\),所以\(A\)、\(B\)一定在同一个大环内。所以我们枚举其中每个点对\((A,B)\),再钦定某个强连通分量内的点\(x\),因为\(A\)、\(B\)一定在同一个大环内,模拟找三元环的过程,就一定可以找出一个三元环\((A,B,x)\)
#include <bits/stdc++.h>
using namespace std;
int n, t, top, ind, low[5005], dfn[5005], que[5005], vis[5005], rec[5005];
char ch[5005][5005];
int read()
{
int x = 0, fl = 1; char ch = getchar();
while (ch < ‘0‘ || ch > ‘9‘) { if (ch == ‘-‘) fl = -1; ch = getchar();}
while (ch >= ‘0‘ && ch <= ‘9‘) {x = (x << 1) + (x << 3) + ch - ‘0‘; ch = getchar();}
return x * fl;
}
void Tarjan(int x)
{
dfn[x] = low[x] = ++ ind;
vis[x] = 1;
que[ ++ top] = x;
for (int y = 1; y <= n; y ++ )
{
if (ch[x][y] != ‘1‘) continue;
if (!dfn[y])
{
Tarjan(y);
low[x] = min(low[x], low[y]);
}
else if (vis[y]) low[x] = min(low[x], dfn[y]);
}
if (low[x] == dfn[x])
{
t = 0;
int now = -1;
do
{
now = que[top -- ];
vis[now] = 0;
rec[ ++ t] = now;
} while (now != x);
for (int i = 1; i <= t - 1; i ++ )
{
for (int j = 1; j <= t - 1; j ++ )
{
if (ch[x][rec[i]] == ‘1‘ && ch[rec[i]][rec[j]] == ‘1‘ && ch[rec[j]][x] == ‘1‘ && i != j)
{
printf("%d %d %d\n", x, rec[i], rec[j]);
exit(0);
}
}
}
}
return;
}
int main()
{
n = read();
for (int i = 1; i <= n; i ++ )
scanf("%s", ch[i] + 1);
for (int i = 1; i <= n; i ++ )
if (!dfn[i])
Tarjan(i);
puts("-1");
return 0;
}
标签:pac 过程 https tchar row lang == ble continue
原文地址:https://www.cnblogs.com/andysj/p/14014551.html