In order to make their sons brave, Jiajia and Wind take them to a big cave. The cave has n rooms, and one-way corridors connecting some rooms. Each time, Wind choose two rooms x and y, and ask one of their little sons go from one to the other. The son can either go from x to y, or from y to x. Wind promised that her tasks are all possible, but she actually doesn’t know how to decide if a task is possible. To make her life easier, Jiajia decided to choose a cave in which every pair of rooms is a possible task. Given a cave, can you tell Jiajia whether Wind can randomly choose two rooms without worrying about anything?
The first line contains a single integer T, the number of test cases. And followed T cases.
The first line for each case contains two integers n, m(0 < n < 1001,m < 6000), the number of rooms and corridors in the cave. The next m lines each contains two integers u and v, indicating that there is a corridor connecting room u and room v directly.
The output should contain T lines. Write ‘Yes’ if the cave has the property stated above, or ‘No’ otherwise.
1
3 3
1 2
2 3
3 1
Yes
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define inf 0X3f3f3f3f
using namespace std;
typedef long long ll;
const int MAXN=1e5+10;
const int MAX=12000+10;
const double eps=1e-6;
int du[MAX];
//强连通模板
int book_stack[MAX]; //标记入栈
int dfn[MAX]; //储存u被搜索的次序
int low[MAX]; //储存u或u的子树能追溯到的最早的栈中的节点次序
int first[MAX]; //链接表
int belong[MAX]; //标记节点属于哪个强连通分量
int n,m,scc,Time,num; //n个节点,m条边,scc强连通分量数量,time次序
stack<int>q; //栈储存节点
struct EDGE{
int v;
int next;
}edge[MAX]; // 链接表
struct NODE{
int u,v;
}node[MAX];
void init(){ //初始化
scc=0;
Time=1;
num=0;
memset(du,0,sizeof(du));
memset(first,-1,sizeof(first));
memset(book_stack,0,sizeof(book_stack));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
}
void addedge(int u,int v){ //建立链接表
edge[num].v=v;
edge[num].next=first[u];
first[u]=num++;
}
void tarjan(int u){ //tarjan核心算法
dfn[u]=low[u]=Time++; //为u设定次序和初始化low
q.push(u); //u入栈
book_stack[u]=1; //标记入栈
for(int i=first[u];i!=-1;i=edge[i].next){ //遍历每一条边
int temp=edge[i].v;
if(!dfn[temp]){ //如果v没有被访问过
tarjan(temp); //继续从v找
low[u]=min(low[u],low[temp]); //判断向后扩展强连通分量
}
else if(book_stack[temp]) //如果v被访问过并且在栈中
low[u]=min(low[u],dfn[temp]); //判断向前合并强连通分量
}
if(dfn[u]==low[u]){ //找到强连通分量的根
int v;
do{
v=q.top();q.pop();
book_stack[v]=0;
belong[v]=scc;
}
while(u!=v);
scc++;
}
}
void get_scc(){
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
}
void tsort(){
int cnt=0;
queue<int>q;
for(int i=n+1;i<=n+scc;i++)
if(du[i]==0){
cnt++;
q.push(i);
}
if(cnt>1){
cout<<"No"<return ;
}
while(q.size()){
int u=q.front();q.pop();
cnt=0;
for(int i=first[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
du[v]--;
if(du[v]==0){
q.push(v);
cnt++;
}
}
if(cnt>1){
cout<<"No"<return ;
}
}
cout<<"Yes"<return ;
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
#endif
int T;
cin>>T;
while(T--){
cin>>n>>m;
init();
for(int i=1;i<=m;i++){
scanf("%d%d",&node[i].u,&node[i].v);
addedge(node[i].u,node[i].v);
}
get_scc();
for(int i=1;i<=n;i++)
belong[i]++;
if(scc==1){
cout<<"Yes"<continue;
}
for(int i=1;i<=m;i++){
int u=belong[node[i].u]+n; //额外建图
int v=belong[node[i].v]+n;
if(u!=v){
addedge(u,v);
du[v]++;
}
}
tsort();
}
return 0;
}