洛谷 p2002 消息扩散 题解以及注意
作者:互联网
题目:
洛谷地址:https://www.luogu.com.cn/problem/P2002
分析:
简单读题后可以想到:
一,tarjan对图进行缩点。
二,求入度为0的点的个数即为答案。
简单的对步骤二的证明:
对于每一个点,如果入度>0,那么它可以从其他点得到消息,当入度为0时,则没有可以给当前顶点传递消息的,那么当前顶点就作为发送消息的节点。
注意:数据很大,递归可能会栈空间溢出,所以在跑tarjan时要叫上inline(主要提醒自己)。
代码:
#include<cstdio> #include<algorithm> using namespace std; #define ll long long int read()//快读 { int f=0,k=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') k=-1;ch=getchar();} while(ch>='0'&&ch<='9'){f=(f<<1)+(f<<3)+(ch^48);ch=getchar();} return f*k; } const int MAXN=1e5+10,MAXM=5e5+10; int head[MAXN],ver[MAXM],nxt[MAXM],tot; int n,m,dfn[MAXN],low[MAXN],number,c[MAXN],cnt,ans,in[MAXN],stack[MAXN],top; bool ins[MAXN]; void add(int x,int y) { ver[++tot]=y,nxt[tot]=head[x],head[x]=tot; } inline void tarjan(int x)//tarjan板子,记得加inline { low[x]=dfn[x]=++number; stack[++top]=x,ins[x]=1; for(int i=head[x];i;i=nxt[i]) { int y=ver[i]; if(!dfn[y]){ tarjan(y); low[x]=min(low[x],low[y]); } else if(ins[y]) low[x]=min(low[x],dfn[y]); } if(low[x]==dfn[x]){ int y;cnt++; do{ y=stack[top--],ins[y]=0; c[y]=cnt; } while(x!=y); } } int main() { n=read(),m=read(); for(int i=1;i<=m;i++){ int x=read(),y=read(); if(x==y) continue;//因为可能有自环,所以要记得特判 add(x,y); } for(int i=1;i<=n;i++)//tarjan if(!dfn[i]) tarjan(i); for(int x=1;x<=n;x++) for(int i=head[x];i;i=nxt[i]){ int y=ver[i]; if(c[x]==c[y]) continue; in[c[y]]++;//缩点不重新建图,直接统计每个点的入读 } for(int i=1;i<=cnt;i++) if(!in[i]) ans++;//统计节点个数 printf("%d\n",ans); return 0; }
标签:p2002,tarjan,ch,洛谷,int,题解,long,while 来源: https://www.cnblogs.com/Zxr123-Zone/p/16461500.html