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:
强连通分量是指非强连通图中的极大强连通子图,求强连通分量的算法常用的有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; }
相关文章推荐
- poj 2186 Popular cows ( tarjan )
- POJ 2186 Popular Cows【Tarjan缩点+建缩点图】
- poj--2186--Popular Cows (scc+缩点)
- poj 2186 Popular Cows
- POJ2186 Popular Cows 【强连通分量】+【Kosaraju】+【Tarjan】+【Garbow】
- POJ 2186 Popular Cows
- POJ 2186 Popular Cows 强连通分量
- Popular Cows--POJ 2186
- 【POJ 2186】Popular Cows(强连通分量_tarjan)
- poj 2186 Popular Cows(强连通)
- Popular Cows poj 2186 tarjan
- POJ 2186 Popular Cows --强连通分量
- POJ 2186 -- Popular Cows (Strongly Connected Components)
- POJ 2186 Popular Cows(Tarjan + 强连通分量缩点)
- POJ 2186 Popular Cows (强联通)
- POJ-2186 Popular Cows (强连通分量[Kosaraju])
- POJ 2186 Popular Cows
- poj 2186 Popular Cows 强连通分量tarjan算法
- poj2186——Popular Cows(tarjan算法)
- poj 2186 Popular Cows (强连通分量+缩点)