您的位置:首页 > 运维架构

POJ_2186_Popular Cows_强连通分量

2016-08-21 20:44 381 查看
PopularCows

TimeLimit:2000MSMemoryLimit:65536K
TotalSubmissions:30680Accepted:12445
Description

Everycow'sdreamistobecomethemostpopularcowintheherd.InaherdofN(1<=N<=10,000)cows,youaregivenuptoM(1<=M<=50,000)orderedpairsoftheform(A,B)thattellyouthatcowAthinksthatcowBispopular.Sincepopularityistransitive,ifAthinksBispopularandBthinksCispopular,thenAwillalsothinkthatCis
popular,evenifthisisnotexplicitlyspecifiedbyanorderedpairintheinput.Yourtaskistocomputethenumberofcowsthatareconsideredpopularbyeveryothercow.
Input

*Line1:Twospace-separatedintegers,NandM

*Lines2..1+M:Twospace-separatednumbersAandB,meaningthatAthinksBispopular.
Output

*Line1:Asingleintegerthatisthenumberofcowswhoareconsideredpopularbyeveryothercow.
SampleInput

33
12
21
23

SampleOutput

1

大意:n只牛,m对数(a,b)表示a认为b牛逼。若a认为b牛逼,b认为c牛逼,那么a也认为c牛逼。问n只牛中,有多少只牛是其他所有牛都认为牛逼的。

分析:若图为不连通,则答案为0.当图连通时,在同一个强连通分量A中的牛在被该强连通分量中其他牛认为牛逼;若在A和另一个强连通分量B之间有路,假设A指向B,则A中的牛都认为B中的牛是牛逼的。任意一个有向图都可以分解成若干不相交的强连通分量,把每个强连通分量缩点,就得到一个DAG(有向无环图)。该题要找的是缩点后DAG中出度为0的点所表示的强连通分量中的点数。(该出度为0的点一定唯一,否则不可能有其他牛都认为牛逼的牛)

求强连通分量可使用tarjan算法。

Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。

定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。

当DFN(u)=Low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。


voidtarjan(ints)
{
vis[s]=2;
dfn[s]=low[s]=++now;
sta.push(s);
for(inti=0;i<gra[s].size();i++)
{
intt=gra[s][i];
if(dfn[t]==0)
{
tarjan(t);
low[s]=min(low[s],low[t]);
}
elseif(vis[t]==2)
low[s]=min(low[s],dfn[t]);
}
if(low[s]==dfn[s])
{
sum++;
while(!sta.empty())
{
intt=sta.top();
sta.pop();
vis[t]=1;
num[t]=sum;
if(t==s)
break;
}
}
}




AC代码:


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stdlib.h>
#include<vector>
#include<stack>
usingnamespacestd;
#defineLLlonglong
#defineN10005
vector<int>gra
;
stack<int>sta;
intn,m,dfn
,low
,vis
,num
;
intdegree
,sum,now,res,loc;
voidinit()
{
sum=0;
now=0;
res=0;
memset(vis,0,sizeof(vis));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(degree,0,sizeof(degree));
for(inti=0;i<=n;i++)
gra[i].clear();
while(!sta.empty())
sta.pop();
}

voidread()
{
inta,b;
scanf("%d%d",&n,&m);
for(inti=0;i<m;i++)
{
scanf("%d%d",&a,&b);
gra[a].push_back(b);
}
}

voidtarjan(ints)
{
vis[s]=2;
dfn[s]=low[s]=++now;
sta.push(s);
for(inti=0;i<gra[s].size();i++)
{
intt=gra[s][i];
if(dfn[t]==0)
{
tarjan(t);
low[s]=min(low[s],low[t]);
}
elseif(vis[t]==2)
low[s]=min(low[s],dfn[t]);
}
if(low[s]==dfn[s])
{
sum++;
while(!sta.empty())
{
intt=sta.top();
sta.pop();
vis[t]=1;
num[t]=sum;//缩点
if(t==s)
break;
}
}
}

voidsolve()
{
for(inti=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
for(inti=1;i<=n;i++)
for(intj=0;j<gra[i].size();j++)
if(num[i]!=num[gra[i][j]])
degree[num[i]]++;//对缩点后的DAG进行出度的统计
for(inti=1;i<=sum;i++)
{
if(degree[i]==0)
{
res++;
loc=i;//第几个强连通分量
}
}
if(res>1)
printf("0\n");
else
{
res=0;
for(inti=1;i<=n;i++)
if(num[i]==loc)
res++;
printf("%d\n",res);
}
}

intmain()
{

init();
read();
solve();
return0;
}
/*
33 12 21 23
*/



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: