思路:
首先发现,如果图中有环,那么竞赛图中肯定可以构造出来,于是我们先把它缩点成DAG,然后考虑怎么做
然后又发现,竞赛图中两两点都是有连接关系的,所以在原图中发现没有关系的两点,那么就不可能构造
所以最终可以推导出DAG一定要是条链
拓扑即可
(特判环的大小为2的情况)
c o d e code code
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
int t, bz;
int n, m, dfn[101000], low[101000], v[101000], stack[101000], top, ru[101000];
int head[101000], tot, head1[101000], tot1, tmp, cnt, c[101000];
struct node
{
int from, next, to;
}b[201000], e[201000];
void add(int x, int y)
{
b[++tot]=(node){x, head[x], y};
head[x]=tot;
}
void add1(int x, int y)
{
e[++tot1]=(node){x, head1[x], y};
head1[x]=tot1;
}
void tarjan(int x)
{
dfn[x]=low[x]=++cnt;
v[x]=1;
stack[++top]=x;
for(int i=head[x]; i; i=b[i].next)
{
int y=b[i].to;
if(!dfn[y])
{
tarjan(y);
low[x]=min(low[x], low[y]);
}
else if(v[y])
low[x]=min(low[x], dfn[y]);
}
if(dfn[x]==low[x])
{
tmp++;
int flag=0;
do
{
flag++;
c[stack[top]]=tmp;
v[stack[top]]=0;
top--;
}
while(x!=stack[top+1]);
if(flag==2)
bz=1;
}
return;
}
bool topu()
{
queue<int> q;
for(int i=1; i<=tmp; i++)
if(!ru[i])
{
if(!q.empty())
return 0;
q.push(i);
}
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head1[x]; i; i=e[i].next)
{
int y=e[i].to;
ru[y]--;
if(!ru[y])
{
if(!q.empty())
return 0;
q.push(y);
}
}
}
return 1;
}
int main()
{
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &n, &m);
for(int i=1; i<=m; i++)
{
int x, y;
scanf("%d%d", &x, &y);
add(x, y);
}
bz=0;
for(int i=1; i<=n; i++)
if(!dfn[i])
tarjan(i);
if(bz)
{
printf("NO\n");
tot=tot1=tmp=cnt=top=0;
memset(head, 0, sizeof(head)), memset(head1, 0, sizeof(head1));
memset(ru, 0, sizeof(ru));
for(int i=1; i<=n; i++)
v[i]=dfn[i]=low[i]=stack[i]=c[i]=0;
continue;
}
for(int i=1; i<=m; i++)
{
int x=b[i].from, y=b[i].to;
if(c[x]!=c[y])
add1(c[x], c[y]), ru[c[y]]++;
}
if(topu())
printf("YES\n");
else printf("NO\n");
tot=tot1=tmp=cnt=top=0;
memset(head, 0, sizeof(head)), memset(head1, 0, sizeof(head1));
memset(ru, 0, sizeof(ru));
for(int i=1; i<=n; i++)
v[i]=dfn[i]=low[i]=stack[i]=c[i]=0;
}
return 0;
}