P2341 Luogu [USACO03FALL][HAOI2006]受欢迎的牛 G
国际惯例:题目链接
题目大意:给定有向图,问有多少个点可以被除自己以外所有点到达。
部分分:按照题意模拟,我每个点跑一次\(Dfs\),暴力统计,看看多少个点可以被所有点达到。
感觉也没啥好说的了...\(Tarjan\)缩点,然后发现如果存在这么一坨点,他们必然是出度为\(0\)的,否则的话,这个点如果能回来,就会并入一个\(SCC\),否则的话,这些点必然不满足的。
从而找出度为\(0\)的就好了,如果有多个,也说明必然是无解,否则就记录这一坨点的个数即可。
#include<bits/stdc++.h>
using namespace std;
#define rint register int
//quick in out
inline void in (int &x){
x = 0; char ch = getchar ();
while(!isdigit(ch)){ch = getchar () ;}
while(isdigit(ch))x = x * 10 + ch - 48,ch = getchar () ;
}
void out (int x){
if(x>9)out(x/10);
putchar(x%10+48);
}
//end quick in out
const int M = 5e4 + 8 , N = 1e4 + 8;
int n , m;
int h[N] , cnt;
struct Edg{
int to,nxt;
inline void add (int u , int v){
nxt = h[u];
to = v;
h[u] = cnt;
}
}e[M << 1];
/*void add(int u,int v){
e[++cnt]=(Edg){v,h[u]};
h[u]=cnt;
}*/
int sta[N] , s , dfn[N] , low[N] , numc , col[N] , tot = 0 , vis[N] , si[N];
void Tarjan (int x){
sta[++ s] = x ;vis[x] = 1;
dfn[x] = low[x] = ++ tot ;
for(rint p = h[x] ; p ; p = e[p].nxt){
int y = e[p].to;
if(!dfn[y]){
Tarjan(y);
low[x] = min(low[x],low[y]);
}
else if(vis[y]){
//low[x] = min(low[x],dfn[y]);
low[x] = min(low[x],low[y]);///只有缩点可以使用的写法
}
}
if(dfn[x] == low[x]){
numc ++;
while(sta[s + 1] != x){
si[numc] ++;
vis[sta[s]] = 0;
col[sta[s]] = numc;
s --;
}
}
}
int deg[N] , ans = 0;
int main(){
in(n),in(m);
for(rint i = 1 ; i <= m ; i ++){
int a,b;
in(a) , in(b);
e[++cnt].add(a , b);
//add(a,b);
}
for(rint i = 1 ; i <= n ; i ++){
if(dfn[i] == 0)Tarjan(i);
}
for(rint i = 1 ; i <= n ; i++){
int c1 = col[i];
for(rint p = h[i] ; p ; p =e[p].nxt){
int c2 = col[e[p].to];
if(c1 != c2){
//e[++m].add(c1 , c2);
deg[c1] ++;
}
}
}
for(rint i = 1 ; i <= numc ; i ++){
if(!deg[i]){
if(ans){
out(0);
//printf("0\n");
return 0;
}
ans = si[i];
}
}
out(ans);
//printf("%d\n",ans);
return 0;
}
我不想就这样沦陷,迷失在黑夜,我将燃烧这生命,就算再壮烈。