洛谷 2341受欢迎的牛
废话真多啊,就是tarjan一遍,缩强连通分量点,建好新的图之后查看是否有出度为0的点。
如果有且仅有一个,那么这一个一定是可以被所有牛喜欢的啦,用cnt数组去记录每一个强连通分量中点的个数,这个可以被所有点到达的强连通分量中点的个数就是answer!
但这只有85分;
因为如果有两个或两个以上出度为0的点,他们是绝对不可能互相到达的了!必须判断是否有且仅有1个出度为0的分量,否则输出0!
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=10000+5;
vector<int> olg[N];
vector<int> reg[N];
stack<int> s;
int seq,num,n,m,a,b,tmp1,tmp2,ans,ok;
int dfn[N],low[N],belong[N],ind[N],cnt[N];
bool ins[N];
void tarjan(int x){ //tarjan的板子
int j;
dfn[x]=low[x]=++seq;
s.push(x);ins[x]=true;
for(int i=0;i<olg[x].size();i++){
j=olg[x][i];
if(!dfn[j]){
tarjan(j);
low[x]=min(low[x],low[j]);
}
else if(ins[j]) low[x]=min(low[x],dfn[j]);
}
if(dfn[x]==low[x]){
++num;
while(s.top()!=x){
cnt[num]++;
belong[s.top()]=num;
ins[s.top()]=false;
s.pop();
}
cnt[num]++;
belong[x]=num;
ins[x]=false;
s.pop();
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){ //建旧图;
scanf("%d%d",&a,&b);
olg[a].push_back(b);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) //没找过的点也许不与任何tarjan跑过的点连接,所以要再跑一次,不从不漏!
tarjan(i);
for(int i=1;i<=n;i++){ //建新图;
tmp1=belong[i];
for(int j=0;j<olg[i].size();j++){
tmp2=belong[olg[i][j]];
if(tmp1!=tmp2){
reg[tmp1].push_back(tmp2);
}
}
}
for(int i=1;i<=num;i++)
if(!reg[i].size()){ //新图中出度为0的点
ok++; //判断是否只有一个
ans+=cnt[i];
}
if(ok==1) //出度为0的只有一个
cout<<ans;
else //出度为0的分量有一个以上的话
cout<<0;
return 0;
}
/*
6 7
1 2
2 1
1 4
3 4
6 4
4 5
5 6
*/
tarjan越来越顺手了!加油!