洛谷 P2002 消息扩散

来源:互联网 发布:php一般用什么开发工具 编辑:程序博客网 时间:2024/06/05 19:05

题目背景
本场比赛第一题,给个简单的吧,这 100 分先拿着。
题目描述
有n个城市,中间有单向道路连接,消息会沿着道路扩散,现在给出n个城市及其之间的道路,问至少需要在几个城市发布消息才能让这所有n个城市都得到消息。
输入输出格式
输入格式:
第一行两个整数n,m表示n个城市,m条单向道路。
以下m行,每行两个整数b,e表示有一条从b到e的道路,道路可以重复或存在自环。
输出格式:
一行一个整数,表示至少要在几个城市中发布消息。
输入输出样例
输入样例#1:
5 4
1 2
2 1
2 3
5 1
输出样例#1:
2
说明
【数据范围】
对于20%的数据,n≤200;
对于40%的数据,n≤2,000;
对于100%的数据,n≤100,000,m≤500,000.
【限制】
时间限制:1s,内存限制:256M
【注释】
样例中在4,5号城市中发布消息。

#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#include<stack>using namespace std;#define MAXN 100005#define MAXM 500005struct Edge{ int to,next; }e[MAXM],ee[MAXM/10];int head[MAXN],belong[MAXN],dfn[MAXN],low[MAXN];stack<int> st;int n,m,tot,cur,visx,sum_edge;int id[MAXN],lik[MAXN],input[MAXN];bool exist[MAXN],vis[MAXN];inline void Add_Edge(int u,int v){ e[++tot].to=v,e[tot].next=head[u],head[u]=tot; }void Tarjan(int u){    dfn[u]=low[u]= ++visx;    st.push(u); exist[u]=true;    for(int i=head[u];i;i=e[i].next){        int v=e[i].to;        if(!dfn[v]){            Tarjan(v);            low[u]=min(low[u],low[v]);        }        else if(exist[v]) low[u]=min(low[u],dfn[v]);    }    if(low[u]==dfn[u]){        int x=-1;  ++cur;        do{            x=st.top(),exist[x]=false;            st.pop(),belong[x]=cur;        }while(x!=u);    }}inline void read(int &x){    register char  c=getchar(); int f=1; x=0;    while(c>'9'||c<'0'){ if(c=='-')f=-1; c=getchar(); }    while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); } x*=f;}void Add_Edge_New(int u,int v){    ee[++sum_edge].to=v,ee[sum_edge].next=lik[u],lik[u]=sum_edge;}inline bool cmp(int a,int b){ return input[a] < input[b]; }void DFS(int u){    if(vis[u]) return;    vis[u]=true;    for(int i=lik[u];i;i=ee[i].next){        int v=ee[i].to;        if(!vis[v]) DFS(v);    }}int Main(){    read(n),read(m);    for(int u,v,i=1;i<=m;++i) read(u),read(v),Add_Edge(u,v);    for(int i=1;i<=n;++i) if(!dfn[i]) Tarjan(i);    for(int i=1;i<=n;++i)        for(int j=head[i];j;j=e[j].next){            int v=e[j].to;            if(belong[v]!=belong[i]){                Add_Edge_New(belong[i],belong[v]);                ++input[belong[v]];            }        }    int Ans=0;    /*for(int i=1;i<=cur;++i) id[i]=i;    sort(id+1,id+cur+1,cmp);    for(int i=1;i<=cur;++i)        if(!vis[id[i]]){            ++Ans;            DFS(id[i]);        }*/    for(int i=1;i<=cur;++i) if(!input[i]) ++Ans;    printf("%d\n",Ans);    return 0;}int Aptal_is_My_Son=Main();int main(int argc,char *argv[]){ ; }

刚开始我想缩点,然后建新图,从入度为0的点开始DFS染色,调试之后A掉,其实并不需要染色,只需要统计新图上入度为零的点的个数就好了。