ZJNU 1269 - 灯塔——高级
根据题目输入可以得到一个有向图
信号可以根据有向图的传递性传递,因此可以说是找到这个有向图的所有父亲即可
但又要考虑可能会出现环这类情况
所以跑一遍强连通分量模板,再根据分块后的图找到入度为0的块,把这些块当作信号发出源,就可以使全图都能够收到信号
所以答案就是入度为0的块的数量
(因为跑完程序刚好卡了时间限制,所以使用了缓冲区读入优化,最终程序耗时78ms)
#pragma GCC optimize(3) #include<bits/stdc++.h> using namespace std; const int N=100005; vector<int> G[N]; stack<int> S; int pre[N],lowlink[N],sccno[N],dfs_clock,scc_cnt,ind[N]; const int bsz=1<<16; char bf[bsz],*head,*tail; inline char gc(){ if(head==tail){ int l=fread(bf,1,bsz,stdin); tail=(head=bf)+l; } return *head++; } inline int read(){ int x=0;char c=gc(); while(!isdigit(c))c=gc(); for(;isdigit(c);c=gc())x=x*10+c-'0'; return x; } inline void write(int x){ if(x>=10)write(x/10); putchar(x%10+'0'); } void dfs(int in){ pre[in]=lowlink[in]=++dfs_clock; S.push(in); int num=G[in].size(); for(int i=0;i<num;i++){ int v=G[in][i]; if(!pre[v]){ dfs(v); lowlink[in]=min(lowlink[in],lowlink[v]); } else if(!sccno[v]) lowlink[in]=min(lowlink[in],pre[v]); } if(lowlink[in]==pre[in]){ scc_cnt++; while(1){ int x=S.top(); S.pop(); sccno[x]=scc_cnt; if(x==in) break; } } } int main(){ int N=read(),M=read(),i,j,a,b; for(i=0;i<M;i++){ a=read(); b=read(); G[a].push_back(b); } dfs_clock=scc_cnt=0; memset(sccno,0,sizeof sccno); memset(pre,0,sizeof pre); for(i=1;i<=N;i++) if(!pre[i]) dfs(i); memset(ind,0,sizeof ind); for(i=1;i<=N;i++){ a=G[i].size(); for(j=0;j<a;j++) if(sccno[i]!=sccno[G[i][j]]) ind[sccno[G[i][j]]]++; } for(a=0,i=1;i<=scc_cnt;i++) if(!ind[i]) a++; write(a); return 0; }