noip模拟题《戏》game

【问题背景】
      zhx 和他的妹子(们) 做游戏。
【问题描述】
      考虑 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
【数据规模与约定】
     对于50%的数据,1 ≤n≤ 500。
     对于80%的数据,1 ≤n≤ 1000。
     对于100%的数据,1 ≤n≤ 5000。

     啦啦啦第一次直接n3暴力了
正解:
     由于这是一个竞赛图,每两个点之间有且仅有一条有向边,所以当我们找到一个任意长度的环时,考虑这个环上的前三个点A,B,C,若C与A之间的边由C指向A,则找到一个三元环,否则从A指向C有一条边,在这个环上删去B,加上C->A的边,就得到了一个点数少一个的环。
     下面只需考虑如何找一个任意长度的环:对图进行dfs,以v数组存下每个点的遍历状态,0表示没有访问过,1表示访问过但从这个点延伸出的路径上的点还没有访问完,2表示已经访问过这个点及它延伸出的路径上所有的点。这样当我们在dfs中发现又扩展到一个状态为1的点,就找到了一个环。

 1 program game(input,output);
 2 var
 3   a:array[0..5050,0..5050]of boolean;
 4   f,v,s:array[0..5050]of longint;
 5   c:char;
 6   i,j,n,m,t:longint;
 7 procedure work;
 8 begin
 9    for i:=1 to m>>1 do begin t:=f[i];f[i]:=f[m-i+1];f[m-i+1]:=t; end;
10    j:=1;
11    for i:=2 to m do if f[i]<f[j] then j:=i;
12    for i:=1 to m do begin t:=i+j-1;if t>m then t:=t-m;v[i]:=f[t]; end;
13    for i:=1 to m do f[i]:=v[i];
14    //writeln(m);
15    //for i:=1 to m do writeln(f[i]);
16    for i:=3 to m do
17       if a[f[i],f[1]] then begin write(f[1],' ',f[i-1],' ',f[i]);close(input);close(output);halt; end;
18 end;
19 procedure dfs(k,d:longint);
20 var
21   i:longint;
22 begin
23    v[k]:=1;
24    s[d]:=k;
25    for i:=1 to n do if a[k,i] then
26       begin
27          if v[i]=2 then continue;
28          if v[i]=1 then
29             begin
30                m:=1;f[1]:=i;j:=d;
31                while s[j]<>i do begin inc(m);f[m]:=s[j];dec(j); end;
32                work;
33             end;
34          dfs(i,d+1);
35       end;
36    v[k]:=2;
37 end;
38 begin
39    assign(input,'game.in');assign(output,'game.out');reset(input);rewrite(output);
40    readln(n);
41    for i:=1 to n do begin for j:=1 to n do begin read(c);if c='1' then a[i,j]:=true else a[i,j]:=false; end;readln; end;
42    for i:=1 to n do if v[i]=0 then dfs(i,1);
43    write(-1);
44    close(input);close(output);
45 end.

 

posted @ 2017-02-06 09:55  Klaier  阅读(252)  评论(0编辑  收藏  举报