题意:给你一个有向图,让你输出其中的一个奇环。
分析:一开始想的先求出强连通分量然后二分图染色,然后发现搞不动,后来想到可以拆点,每个点拆成两个点,分别表示奇数访问和偶数访问,然后一遍DFS,开一个栈保留当然栈中的点,如果栈中同时出现了一个点的奇状态和偶状态,那么一定找到了一个奇环,输出就可以了。
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#define INF 0x3f3f3f3f
#define eps 1e-9
#define MAX 100005
using namespace std;
vector<int> G[MAX];
vector<int> S;
int T,n,m,ans[MAX],fa[2*MAX],scc_cnt;
bool jud[MAX*2],jud2[MAX*2];
int dfs(int u,int color)
{
jud[u + color*n] = true;
jud2[u + color*n] = true;
if(jud2[u] && jud2[u+n]) return u + color*n;
for(int v : G[u])
if(!jud[v + (color^1)*n])
{
fa[v + (color^1)*n] = u + color*n;
int num = dfs(v,color^1);
if(num) return num;
}
jud2[u + color*n] = false;
return 0;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++) G[i].clear();
for(int i = 1;i <= m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
G[x].push_back(y);
}
memset(jud,0,sizeof(jud));
memset(jud2,0,sizeof(jud2));
memset(fa,0,sizeof(fa));
bool flag = false;
for(int i = 1;i <= n;i++)
if(!jud[i] && !jud[i+n])
{
int num = dfs(i,1);
if(num)
{
int tot = 0,yl = num;
while(true)
{
if(num > n) ans[++tot] = num-n;
else ans[++tot] = num;
num = fa[num];
if((num % n) == (yl % n)) break;
}
printf("1\n");
printf("%d\n",tot);
for(int i = 1;i <= tot;i++) printf("%d\n",ans[tot-i+1]);
flag = true;
break;
}
}
if(!flag) printf("-1\n");
}
}