P2341 Luogu [USACO03FALL][HAOI2006]受歡迎的牛 G
阿新 • • 發佈:2020-12-22
國際慣例:題目連結
題目大意:給定有向圖,問有多少個點可以被除自己以外所有點到達。
部分分:按照題意模擬,我每個點跑一次\(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; }