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

POJ2186 Popular Cows

2011-10-07 21:47 281 查看
强连通分量+点压缩

强连通分量是指非强连通图中的极大强连通子图,求强连通分量的算法常用的有Tarjan和Kosaraju两种,它们的复杂度均为O(n+m),n图中点的个数,m为边的个数。只看了下Tarjan,没有仔细了解Kosaraju。这里有对Tarjan比较详细的说明,说的都很好:

http://www.byvoid.com/blog/scc-tarjan/

/article/6007404.html

这道题总的过程就是首先利用Tarjan求出所有的强连通分量,然后将每个强连通分量当作一个点(即点压缩,因为在强连通分量内部所有的点都是两两可到达的)。然后求每个强连通分量的出度,题目最终的答案则为出度为0的强连通分量内点的个数。具体证明可见:

http://www.cppblog.com/RyanWang/archive/2009/02/26/74984.aspx

算法证明:

1:假设a和b都是最受欢迎的cow,那么,a欢迎b,而且b欢迎a,于是,a和b是属于同一个连通分量内的点,所有,问题的解集构成一个强连通分量。

2:如果某个强连通分量内的点a到强连通分量外的点b有通路,因为b和a不是同一个强连通分量内的点,所以b到a一定没有通路,那么a不被b欢迎,于是a所在的连通分量一定不是解集的那个连通分量。

3:如果存在两个独立的强连通分量a和b,那么a内的点和b内的点一定不能互相到达,那么,无论是a还是b都不是解集的那个连通分量,问题保证无解。

4:如果图非连通,那么,至少存在两个独立的连通分量,问题一定无解。

AC_CODE:

#include <stdio.h>
#include <memory.h>

#define N 10001
#define M 50001

struct edge
{
int v;
edge *next;
};
edge *vertices
;
edge edges[M];
int cnt;
int idx;
int dfn
;
int low
;
int instack
;
int stack[M];
int top=-1;
int scc
;
int nscc;//强连通分量的编号
int outd
;

void tarjan(int u)
{
int v;
edge *head=vertices[u];
dfn[u]=low[u]=++idx;
stack[++top]=u;
instack[u]=1;
for(;head;head=head->next)
{
v=head->v;
if(!dfn[v])
{
tarjan(v);
low[u]=(low[u]<low[v])?low[u]:low[v];
}
else if(instack[v])
low[u]=(low[u]<dfn[v])?low[u]:dfn[v];
}
if(low[u]==dfn[u])
{
++nscc;
do
{
v=stack[top--];
scc[v]=nscc;
instack[v]=0;
}while(u!=v);
}
return;
}
void calc_outd(int n)
{
int ans=0,cnt=0,v;
edge *head;
for(int i=1;i<=n;i++)
{
head=vertices[i];
for(;head;head=head->next)
{
if(scc[head->v]!=scc[i])
outd[scc[i]]++;
}
}
for(int i=1;i<=nscc;i++)
{
if(!outd[i])
{
v=i;
cnt++;
}
}
//只有出度为0的强连通分量个数为1时,才有解
if(cnt==1)
{
for(int j=1;j<=n;j++)
if(scc[j]==v) ans++;
}
printf("%d\n",ans);
}
int main()
{
int n,m,a,b;
scanf("%d%d",&n,&m);
memset(vertices,0,sizeof(vertices));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(instack,0,sizeof(instack));
memset(outd,0,sizeof(outd));
while(m--)
{
scanf("%d%d",&a,&b);
edges[cnt].v=b;
edges[cnt].next=vertices[a];
vertices[a]=&edges[cnt++];
}
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
calc_outd(n);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: