题目描述
有n个队伍打了m场比赛。如果存在一些队伍,a1,a2,…,ak使得a1赢过了a2,a2赢过a3,…,ak赢过a1,就显得比赛很不公平,且k越大越不公平。反过来说,
如果这些队伍满足a1赢过a2,a2输过a3,a3赢过a4,…,ak输过a1,那比赛就显得很公平,且k越小越公平。具体的说,我们希望找到a1,a2,…,ak这k支队伍(可以重复),并且存在m1,m2,…,mk这k场比赛(比赛不能重复)(为了方便令m0也表示mk,a0也表示ak),使得对于所有的0≤i≤k-1,mi在ai和ai+1之间进行,且对于所有的0≤i≤k-1,比赛mi(m0即为mk)和mi+1的结果对于ai+1是相同的(结果相同意味着ai+1输了这两场比赛或者赢了这两场比赛)。现在给出若干场比赛,试选出这k支队伍(可以重复)以显得比赛很公平,或者判
定这样的k不存在。k存在的情况下,还要尽量小(有些数据不要求k尽量小)。
输入描述:
输入的第一行包含0或者1。1意味着后面每组数据只要正确判断能否找到满足条件的k个队伍并在能找出时输出这k个队伍即为正确,不需要最小化k。0意味着必须最小化k才算正确。接下来有至多6组数据(共享6秒时限)。第一行两个正整数n和m表示队伍的数量比赛的数量(1≤n≤5000,1≤m≤min(1000000,n⋅(n−1)))。接下来每行两个正整数a和b表示队伍a战胜了队伍b(1≤a,b≤n)。 保证一个队伍不会战胜另一个队伍两次。但是两个队伍可能互相战胜过。为了方便,输入的最后有一行单独的0。
输出描述:
第一行输出一个整数k(1≤k≤1000000)表示选出的队伍的数量,这个数量应该尽可能的小(除了某些测试点)。如果无法选出则在第一行输出−1且不需要输出第二行。 第二行输出k个整数a1,…,ak表示题目要求的k个队伍(可以重复)。
示例1
输入
0
6 8
1 2
3 2
3 6
1 6
2 5
3 5
4 6
4 1
0
输出
4
1 6 3 2
说明
输出的环可以从任意位置开始,顺时针逆时针均可。如
4
6 1 2 3
和
4
6 3 2 1
也算正确。
备注:
对于30%的数据,只要正确判断能否找到并在可以找到时输出k个满足条件的队伍即可得分,不需要让k尽量小。对于另外30%的数据,有
1≤n≤1000。
思路
本题给定了一个有向图,要求找出一个环,其中可以有重点但是不能有重边, 且环上的边方向是交错的。
我们可以把每个点拆成两个点a赢和a输,分别表示这个点在环上是作为赢两 次的点出现或者输两次的点出现。那么一场比赛a赢了b,就相当于从a赢连 到b输的一条边,或者从b输连到a赢的一条边。原来的一个环可以对应到拆 点以后的一个环。
现在我们得到了一个二分图,而且是无向的。无向图找最小环可以用bfs解决。 暴力可以得100分,即从每个点开始找到最小环就break(可以证明如果一个 无向图的平均度数至少是8,那么它一定包含一个环。所以bfs时只要搜索最 多5000*8条边,一定会找到环并break。)。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=5050,M=1e6+500;
int gti(void)
{
char c=getchar();
int ret=0,st=1;
for (;!isdigit(c);c=getchar()) if (c=='-') st=-1;
for (;isdigit(c