Luogu2341 受欢迎的牛
好题。
在有向图中找到强连通子图,缩点,记上里面有几头牛,变成DAG。
然后找出出度为0的点。如果这样的点的数量不等于1显然输出0。否则答案就是这个点的原点数。
为了方便,反向建边,变统计出度为入度。枚举每一个原图的点u,如果找到原图中与u点相连的v不属于同一个scc,那么入度+1。(即不重建图。
打了四遍这个题真TM爽
#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 10001
#define maxm 50001
using namespace std;
int head[maxn];
struct edge{
int to, nxt;
}e[maxm];
int n, m, tot, top, cnt, col;
int dfn[maxn], st[maxn], low[maxn], scc[maxn];
int sl[maxn], ind[maxn];
void add(int u, int v){
e[++tot].nxt=head[u];
e[tot].to=v;
head[u]=tot;
}
void tarjan(int u){
dfn[u]=low[u]=++cnt;
st[++top]=u;
for(int i=head[u]; i; i=e[i].nxt){
int v=e[i].to;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u], low[v]);
}else if(!scc[v])
low[u]=min(low[u], dfn[v]);
}
if(low[u]==dfn[u]){
scc[u]=++col;
++sl[col];
while(st[top]!=u){
++sl[col];
scc[st[top]]=col;
top--;
}
top--;
}
}
int main(){
scanf("%d%d", &n, &m);
int x, y;
for(int i=1; i<=m; i++){
scanf("%d%d", &x, &y);
add(y,x);
}
for(int i=1; i<=n; i++)
if(!dfn[i]) tarjan(i);
for(int i=1; i<=n; i++)
for(int j=head[i]; j; j=e[j].nxt){
int v=e[j].to;
if(scc[i]!=scc[v])
ind[scc[v]]++;
}
int ans=0, indtj=0;
for(int i=1; i<=col; i++)
if(!ind[i])
ans=sl[i], indtj++;
if(indtj==1)
printf("%d", ans);
else printf("0");
return 0;
}
不如吃茶去