题目大意:
每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这
种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头
牛被所有的牛认为是受欢迎的。
先用tarjan求出每个强连通分量,再缩点,统计每个点的出度,如果有且只有1个出度为0的点,就输出这个点包含的节点数,否则输出0.
证明:
如果有强连通分量被孤立(即和其他强连通分量无边相连),那么答案一定是0,此时由于缩点后是一个DAG图,出度为0的点的个数一定大于1.
如果没有点被孤立,当出度为0的点多于1个时,由DAG图的性质可得,一定不存在一个点能从其他所有点到达。只有当出度为0的点的个数等于1时,这个出度为0的点才能被其他所有点到达。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; #define cls(s,h) memset(s,h,sizeof s) const int maxn = 1e5 + 7; int n , m ; int tot; struct edge { int to,from,nxt; }e[maxn << 1]; int head[maxn]; void add_edge(int u , int v ){ e[tot].from = u ; e[tot].to = v; e[tot].nxt = head[u]; head[u] = tot++; } int stack[maxn << 1],low[maxn << 1],dfn[maxn << 1]; int scc,sz[maxn << 1],c[maxn << 1],st,num; void init(){ cls(head,-1); cls(e,0); cls(sz,0); scc = 0; st = 0; } void tanjan(int u){ stack[++st] = u; dfn[u] = low[u] = ++ num; for(int i = head[u],v; ~i ;i = e[i].nxt){ if(c[v = e[i].to]) continue; if(dfn[v]) low[u] = min(low[u],dfn[v]); else tanjan(v),low[u] = min(low[u],low[v]); } if(low[u] == dfn[u]){ c[u] = ++ scc; sz[scc] = 1; while(st && u != stack[st]) //SCC number and the scc ge SCC c[stack[st--]] = scc,sz[scc] ++; st--; } } int out[maxn << 1]; int main(int argc, char const *argv[]) { init(); scanf("%d %d",&n,&m); for(int i = 1,u,v;i <= m ;i ++) scanf("%d %d",&u,&v),add_edge(u,v); for(int i = 1;i <= n;i ++) if(!dfn[i]) tanjan(i); for(int i = 0;i < tot;i ++) if(c[e[i].from] != c[e[i].to]) out[c[e[i].from]] ++; int ans = 0; for(int i = 1;i <= scc;i ++) if(!out[i]) ans = ans ? -1: i; if(~ans) ans = sz[ans]; else ans = 0; printf("%d ", ans); return 0; }
//如果没有点被孤立,当出度为0的点多于1个时, //由DAG图的性质可得,一定不存在一个点能从其他所有点到达。 //只有当出度为0的点的个数等于1时, //这个出度为0的点才能被其他所有点到达。 //因为如果存在两个,那么就会少一个点 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; #define cls(s,h) memset(s,h,sizeof s) const int maxn = 1e5 + 7; int n , m ; int tot; struct edge { int to,from,nxt; }e[maxn << 1]; int head[maxn]; void add_edge(int u , int v ){ e[tot].from = u ; e[tot].to = v; e[tot].nxt = head[u]; head[u] = tot++; } int stack[maxn << 1],low[maxn << 1],dfn[maxn << 1]; int scc,sz[maxn << 1],c[maxn << 1],st,num; void init(){ cls(head,-1); cls(e,0); cls(sz,0); scc = 0; st = 0; } void tanjan(int u){ stack[++st] = u; dfn[u] = low[u] = ++ num; for(int i = head[u],v; ~i ;i = e[i].nxt){ if(c[v = e[i].to]) continue; if(dfn[v]) low[u] = min(low[u],dfn[v]); else tanjan(v),low[u] = min(low[u],low[v]); } if(low[u] == dfn[u]){ c[u] = ++ scc; sz[scc] = 1; while(st && u != stack[st]) //强连通分量的编号和其中点的个数 //SCC number and the scc ge SCC c[stack[st--]] = scc,sz[scc] ++; st--; } } int out[maxn << 1]; int main(int argc, char const *argv[]) { init(); scanf("%d %d",&n,&m); for(int i = 1,u,v;i <= m ;i ++) scanf("%d %d",&u,&v),add_edge(u,v); for(int i = 1;i <= n;i ++) if(!dfn[i]) tanjan(i); for(int i = 0;i < tot;i ++) if(c[e[i].from] != c[e[i].to]) out[c[e[i].from]] ++; int ans = 0; for(int i = 1;i <= scc;i ++) if(!out[i]) ans = ans ? -1: i; if(~ans) ans = sz[ans]; else ans = 0; printf("%d ", ans); return 0; }