zybnxy
2019-01-30 12:55:44
题目传送门
标签:
有向图强连通分量:在有向图
事实上,你大概可以理解为:如果一个图的子图中,任意两点可以相互到达,那么这就组成了一个强联通分量。
如果还不理解怎么办?没关系,我们上图像来理解
如图,在这个有向图中,一共有
我们需要两个非常重要的数组,在这里先说明一下
(3)、遍历
(4)、假设我们已经
至此,
那么如果
再结合一下
如果已经被弹掉了,说明无论如何这个点也不能与
如果还在栈里,说明这个点肯定能到达
接下来,就是非
从节点
之后返回节点
返回节点
继续回到节点
至此,
程序实现代码如下
inline int tarjan(int u)
{
low[u]=dfn[u]=++dfn_sum;
stack[top++]=u;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(dfn(v))
low[u]=min(low[u],dfn[v]);
else
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
}
if(low[u]==dfn[u])
{
int now=stack[--top];s_sum++;
s[u]+=s_sum;
while(now!=u)
{
s[now]=s_num;
now=s[--top];
}
}
}
所以,我们再来分析一下这道题。
首先,不难发现,如果这所有的牛都存在同一个强联通分量里。那么它们一定互相受欢迎。
那么,我们怎么来找明星呢。
很简单,找出度为
此题还有一个特殊情况:
如果有两个点分别满足出度为零的条件,则没有明星,这样无法满足所有的牛喜欢他。
有了上边的解释,题目就不是那么难了,代码如下
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int maxn=1e4+5;
const int maxm=5e4+5;
int to[maxm],nex[maxm],fir[maxn];
int col,num,dfn[maxn],low[maxn],de[maxn],si[maxn];
int tot=0,co[maxn],n,m;
int top,st[maxn];
template<class T> inline void read(T &x)
{
x=0;
register char c=getchar();
register bool f=0;
while (!isdigit(c)) f ^=c=='-',c=getchar();
while (isdigit(c)) x=x*10+c-'0',c=getchar();
if(f)x=-x;
}
template <class T> inline void print(T x)
{
if(x<0)putchar('-'),x=-x;
if(x>9)print(x/10);
putchar('0'+x%10);
}
inline void ins(int x,int y)
{
to[++tot]=y;
nex[tot]=fir[x];
fir[x]=tot;
}
void Tarjan(int u)
{
dfn[u]=low[u]=++num;
st[++top]=u;
for(int i=fir[u];i;i=nex[i])
{
int v=to[i];
if(!dfn[v])
{
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(!co[v])low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
co[u]=++col;
++si[col];
while(st[top]!=u)
{
++si[col];
co[st[top]]=col;
--top;
}
--top;
}
}
int main()
{
int x,y;
read(n);read(m);
for(ri i=1;i<=m;i++)
{
read(x);read(y);
ins(y,x);
}
for(ri i=1;i<=n;i++)
if(!dfn[i])Tarjan(i);
for(ri i=1;i<=n;i++)
for(ri j=fir[i];j;j=nex[j])
if(co[i]!=co[to[j]])de[co[to[j]]]++;
int ans=0,u=0;
for(ri i=1;i<=col;i++)if(!de[i])ans=si[i],u++;
if(u==1)print(ans);
else print(0);
return 0;
}