链接:https://ac.nowcoder.com/acm/contest/330/F
来源:牛客网
Applese 的QQ群
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
Applese 有一个QQ群。在这个群中,大家互相请教问题。如 b 向 a 请教过问题,就把 a 叫做是 b 的"老板"。这样一个群中就会有很多老板。
同时规定:如果 a 是 b 的老板,b 是 c 的老板,那么 a 也是 c 的老板。
为了不破坏群里面和谐交流的氛围,Applese 定了一个群规:不允许出现 a 既是 b 的老板, b 又是 a 的老板。
你需要帮助 Applese 判断大家是否遵守了群规。
输入描述:
第一行两个整数 n, m,表示群里的人数以及请教问题的数量。 接下来 m 行,每行两个整数 a, b,表示 a 是 b 的"老板",即 b 向 a 请教了一个问题。 注:无论是否违反了群规,a 都会成为 b 的老板。
输出描述:
对于每次提问,输出一行"Yes"表示大家都遵守了群规,反之输出"No"。
示例1
输入
4 4 1 2 2 3 3 1 1 4
输出
Yes Yes No No
备注:
1≤n≤1051≤n≤105 1≤m≤2⋅1051≤m≤2⋅105 1≤a,b≤n
判断图是否成环有两种做法,一个是二分+拓扑排序和dfs判断的方法。
二分+拓扑排序:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100005;
int n,m;
int in[N];
struct node{
int s,e;
}edge[N<<1];
int check(int mid){
memset(in,0,sizeof(in));
vector<int>v[N];
for(int i=1;i<=mid;i++){
v[edge[i].s].push_back(edge[i].e);//建图
in[edge[i].e]++;
}
int sum=0;
queue<int>q;
for(int i=1;i<=n;i++)
if(!in[i]) q.push(i);
while(q.size()){
int x=q.front();q.pop();
sum++;
for(int i=0;i<v[x].size();i++){
in[v[x][i]]--;
if(in[v[x][i]]==0) q.push(v[x][i]);
}
}
return sum==n;//出来的点的总数为n说明不存在环
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d",&edge[i].s,&edge[i].e);
int l=1,r=m,ans;
while(l<=r){
int mid=l+(r-l)/2;
if(check(mid)){//此时中点前面不存在环,存在环的点在右边
l=mid+1;
ans=mid;//记录不存在环的最后一个点
}else{
r=mid-1;
}
}
for(int i=1;i<=ans;i++) printf("Yes\n");
for(int i=ans+1;i<=m;i++) printf("No\n");
return 0;
}
dfs方法:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100005;
vector<int>v[N];
int dfs(int a,int b){
for(int i=0;i<v[a].size();i++){
if(v[a][i]==b) return 1;//a的老板是b
if(dfs(v[a][i],b)) return 1;//dfs a的老板的老板是b 返回1
}
return 0;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
int flag=0;
while(m--){
int a,b;
scanf("%d%d",&a,&b);//a是b的老板
if(flag||dfs(a,b)){//dfs a的老板是不是b
flag=1;
printf("No\n");
}else{
v[b].push_back(a);
printf("Yes\n");
}
}
return 0;
}