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;
}

 

posted @ 2020-01-26 21:14  StelaYuri  阅读(95)  评论(0编辑  收藏  举报