题目大意:
给你一个关系图,判断是否合法,
每个人都有师父和徒弟,可以有很多个;
且 若A是B的师父,B是C的师父,则A是C的师父。
不合法的情况:
1) 互为师徒;
2) 你的师父是你徒弟的徒弟,或者说你的徒弟是你师父的师父。(3元环或多元环)
题目链接:点击做题
简单理解就是:
判断有向图中是否存在至少3元环;
也就是判断有没有回路自环啥的东西;
此题至少有三种做法。
有向图,无向图判断环的方法及判断负环的方法:
有向图判断环的方法:
1. DFS标记白灰黑
2. 拓扑排序
3. Tarjan
无向图判断环的方法:
1. 改动的拓扑排序(BFS:du[i]<=1,push)
2. DFS标记白灰黑
3. 并查集
拓扑序和rdfs序与遍历图的顺序无关,是不变的。
一个无向完全图给部分边定向后若不存在环,则总有一种给其他边定向的方式使得这个有向图无环
有向图判断环的方法:
无向图判断环的方法:
改动的拓扑排序(BFS:du[i]<=1,push)
DFS标记白灰黑
并查集
法一:拓扑排序
1) . 统计每个点的入度;
2) . 将入度为0的点加入队列;
3) . 出去队首元素,将此元素所连接的点入度减一,若此后入度为0则加入队列;
4.) 判断队列循环次数,若等于n则不存在回路,则此关系图合法;
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<stack>
#include<vector>
#include<ctime>
using namespace std;
const int N = 2005;
const int M = 3000005;
int n,m;
int tot,flag;
int in[N],head[N];
struct lp
{
int u,v,nex;
lp(){}
lp(int a,int b,int c):
u(a),v(b),nex(c){}
}cw[N];
void add(int a,int b){
cw[++tot]=lp(a,b,head[a]);
head[a]=tot;
}
void tuopu(){
queue<int>Q;
while(!Q.empty())Q.pop();
for(int i=0;i<n;++i){
if(in[i]==0)Q.push(i);
}
int t=0;
while(!Q.empty()){
t++;
int u=Q.front();Q.pop();
for(int i=head[u];i!=-1;i=cw[i].nex){
int v=cw[i].v;
in[v]--;
if(in[v]==0)Q.push(v);
}
}
if(t==n)flag=1;
}
int main(int argc, char const *argv[])
{
int a,b;
while(~scanf("%d%d",&n,&m)&&(n)){
memset(in,0,sizeof(in));
tot=-1;
memset(head,-1,sizeof(head));
for(int i=0;i<m;++i){
scanf("%d%d",&a,&b);
add(a,b);
in[b]++;
}
flag=0;
tuopu();
if(flag)printf("YES\n");
else printf("NO\n");
}
return 0;
}
法二:tarjan
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<stack>
#include<vector>
#include<ctime>
using namespace std;
const int N = 105;
const int M = 3000005;
int n,tot,flag,idex;
int head[N],vis[N];
int low[N],dfn[N];
int qltNum;
int qltMap[N];
stack<int>st;
struct lp
{
int to,nex;
lp(){}
lp(int a,int b):
to(a),nex(b){}
}cw[N*N];
void add(int a,int b){
cw[++tot]=lp(b,head[a]);
head[a]=tot;
}
void dfs(int u,int fa){
dfn[u]=low[u]=++idex;
vis[u]=1;
st.push(u);
int v;
for(int i=head[u];i!=-1;i=cw[i].nex){
v=cw[i].to;
if(v==fa){
flag=1;
break;
}
if(!vis[v]){
dfs(v,u);
if(flag)return;
low[u]=min(low[u],low[v]);
//if(low[v] > dfn[u]) bridge
}else if(vis[v]==1){
low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u]){
qltNum++;
int t=0;
do{
t++;
v=st.top();st.pop();
vis[v]=2;
qltMap[v]=qltNum;
if(t>=3){
flag=1;
return;
}
}while(v!=u);
//cout<<t<<"\n";
}
}
void tarjan(){
for(int i=1;i<=n;++i){
if(!vis[i]){
dfs(i,-1);
}
if(flag)return;
}
}
void init(){
while(!st.empty())st.pop();
qltNum=idex=flag=0;
tot=-1;
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
memset(qltMap,0,sizeof(qltMap));
}
#define DEBUG
int main(int argc, char const *argv[]) {
int a,b,m;
#ifdef DEBUG
freopen("D:in.in", "r", stdin);
freopen("D:out.out", "w", stdout);
#endif
while(~scanf("%d%d",&n,&m)&&(n)){
init();
memset(head,-1,sizeof(head));
for(int i=0;i<m;++i){
scanf("%d%d",&a,&b);
a++,b++;
add(a,b);
}
tarjan();
if(flag)printf("NO\n");
else printf("YES\n");
}
return 0;
}