【问题描述】
考虑 N 个人玩一个游戏,任意两个人之间进行一场游戏(共 N*(N-1)/2 场),
且每场一定能分出胜负。
现在,你需要在其中找到三个人构成“剪刀石头步”局面:三个人 A,B,C
满足 A 战胜 B,B 战胜 C,C 战胜 A。
【输入格式】
第一行一个正整数 N,表示参加游戏的人数。
接下来 N 行,每行 N 个数 0/1,中间没有空格隔开。第 i 行第 j 列数字为 1
表示 i 在游戏中战胜了 j。所有对角线元素(即第 i 行第 i 个元素)为 0,保证数
据合法。
【输出格式】
如果存在三个人构成“剪刀石头布”局面,输出三个人的编号(从 1 开始)。
如果不存在这样的三个人,输出一个数-1。
【样例输入】
5
00100
10000
01001
11101
11000
【样例输出】
1 3 2
【数据规模与约定】
55。
80%的数据,1 ≤ 푁 ≤ 10。
考虑 N 个人玩一个游戏,任意两个人之间进行一场游戏(共 N*(N-1)/2 场),
且每场一定能分出胜负。
现在,你需要在其中找到三个人构成“剪刀石头步”局面:三个人 A,B,C
满足 A 战胜 B,B 战胜 C,C 战胜 A。
【输入格式】
第一行一个正整数 N,表示参加游戏的人数。
接下来 N 行,每行 N 个数 0/1,中间没有空格隔开。第 i 行第 j 列数字为 1
表示 i 在游戏中战胜了 j。所有对角线元素(即第 i 行第 i 个元素)为 0,保证数
据合法。
【输出格式】
如果存在三个人构成“剪刀石头布”局面,输出三个人的编号(从 1 开始)。
如果不存在这样的三个人,输出一个数-1。
【样例输入】
5
00100
10000
01001
11101
11000
【样例输出】
1 3 2
【数据规模与约定】
55。
80%的数据,1 ≤ 푁 ≤ 10。
对于100%的数据,1 ≤ 푁 ≤ 5000
分析:
理论上这是一个竞赛图,竞赛图有一个重要的性质,就是如果存在一个环(包含两个以上结点的环),就一定存在一个三元环,即题意的石头剪刀布局面。
下面来证明此性质:
假设1->2,2->3,3->4,4->5,5->1,我们来证明存在三元环。
因为1->2,2->3,所以如果3->1,就一定会存在三元环,
如果3不能打败1,那么就是1打败3,这就是竞赛,所以有1->3,那么这时环中就减少了一个结点,
同理,我们还可以一直减少结点,那么最终一定会得到三元环。
至于有向图找环,那就是求强连通分量。
参考程序:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=5100;
const int maxm=5100;
char tmp[maxn];
int cycle[maxn],stack[maxn],dfn[maxn],spos[maxn];
int a[maxm][maxm];
int top=0,Time=0,n,len=0;
bool tarjan(int u){
dfn[u]=1;
stack[top++]=u;
spos[u]=top-1;
for (int i=1;i<=n;i++)
if (a[u][i]){
if (dfn[i]==1){
len=top-spos[i];
memcpy(cycle,stack+spos[i],sizeof(int)*len);
return true;
}else if (!dfn[i]){
bool ok=tarjan(i);
if (ok)return true;
}
}
top--;dfn[u]=2;
return false;
}
void print(){
for (int i=1;i<len-1;i++)
if (a[cycle[i+1]][cycle[0]])
printf("%d %d %d\n",cycle[0],cycle[i],cycle[i+1]);
}
int main(){
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("\n%s",tmp+1);
for (int j=1;j<=n;j++)
a[i][j]=tmp[j]=='1';
}
for (int i=1;i<=n;i++)
if (!dfn[i])
if (tarjan(i)){
print();
return 0;
}
printf("-1");
return 0;
}