POJ2186 强连通分支(Strongly_Connected_Components)
2011-03-21 12:17
267 查看
这个题如果用传递闭包,显然是不行的。结点有10000个,效率O(N*N*N)
还好有个Korasaju算法:
procedure Strongly_Connected_Components(G);
begin
1.深度优先遍历G,算出每个结点u的结束时间f[u],起点如何选择无所谓。
2.深度优先遍历G的转置图GT,选择遍历的起点时,按照结点的结束时间从大到小进行。遍历的过程中,一边遍历,一边给结点做分类标记,每找到一个新的起点,分类标记值就加1。
3. 第2步中产生的标记值相同的结点构成深度优先森林中的一棵树,也即一个强连通分量
end;
这里将同一强连通分支的结点弄成一个点,然后找出度为0的点,如果出度为0的点只有一个,那么可解,解为出度为0的强连通分支上的所有点的个数。
对于DAG图有个定理:DAG图中唯一出度为0的点,一定可以由任何点出发均可达(由于无环,所以从任何点出发往前走,必然终止于一个出度为0的点);
#include <iostream>
#include <vector>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXM=50000;
const int MAXN=10000;
int finish[MAXN+5];
vector<int> adjacent[MAXN+5];
vector<int> radjacent[MAXN+5];
bool visit[MAXN+5];
int finishtime;
int distribute[MAXN+5];
bool same[MAXN+5];
void dfs(int u)
{
int size;
int i;
visit[u]=true;
size=adjacent[u].size();
for(i=0;i<size;i++)
{
if(visit[adjacent[u][i]]==false)
{
visit[adjacent[u] [i]]=true;
dfs(adjacent[u][i]);
}
}
finishtime++;
finish[finishtime]=u;
}
void rdfs(int u,int num)
{
int i;
int size=radjacent[u].size();
visit[u]=true;
distribute[u ]=num;
for(i=0;i<size;i++)
{
if(visit[radjacent[u][i]]==false)
{
visit[radjacent[u][i]]=true;
distribute[radjacent[u][i]]=num;
rdfs(radjacent[u][i],num);
}
}
}
int main()
{
int N,M;
int i;
int j;
int from,to;
while(scanf("%d %d",&N,&M)!=EOF)
{
for(i=1;i<=M;i++)
{
scanf("%d %d",&from,&to);
adjacent[from].push_back(to);
radjacent[to].push_back(from);//图的转置
}
finishtime=0;
memset(visit,false,sizeof(visit));
for(i=1;i<=N;i++)
{
if(visit[i]==false)
{
dfs(i);
}
}//对图DFS,按结束时间进栈,先结束先进栈
memset(visit,false,sizeof(visit));
int num=1;
for(i=finishtime;i>=1;i--)
{
if(visit[finish[i]]==false)
{
rdfs(finish[i],num);
num++;
}
}//对转置的图DFS,按出栈顺序DFS
num--;
memset(same,0,sizeof(same));
for(i=1;i<=N;i++)
{
for(j=0;j<adjacent[i].size();j++)
{
if(distribute[i]!=distribute[adjacent[i][j]])
{
same[distribute[i]]=1;//标记出度不为0的块
}
}
}
int sub;
int same_sum=0;
for(i=1;i<=num;i++)
{
if(same[i]==0)
{
sub=i;
same_sum++;//统计出度为0的块的个数
}
}
int ans;
ans=0;
if(same_sum>1)
{
printf("0/n");
continue;
}//出度为0的块的数量超过1
else
{
for(i=1;i<=N;i++)
{
if(distribute[i]==sub)
{
ans++;
}
}//统计出度为0的块的节点的个数
printf("%d/n",ans);
}
}
return 0;
}
参考文献:北大2010summerschool的gw_connect.ppt
还好有个Korasaju算法:
procedure Strongly_Connected_Components(G);
begin
1.深度优先遍历G,算出每个结点u的结束时间f[u],起点如何选择无所谓。
2.深度优先遍历G的转置图GT,选择遍历的起点时,按照结点的结束时间从大到小进行。遍历的过程中,一边遍历,一边给结点做分类标记,每找到一个新的起点,分类标记值就加1。
3. 第2步中产生的标记值相同的结点构成深度优先森林中的一棵树,也即一个强连通分量
end;
这里将同一强连通分支的结点弄成一个点,然后找出度为0的点,如果出度为0的点只有一个,那么可解,解为出度为0的强连通分支上的所有点的个数。
对于DAG图有个定理:DAG图中唯一出度为0的点,一定可以由任何点出发均可达(由于无环,所以从任何点出发往前走,必然终止于一个出度为0的点);
#include <iostream>
#include <vector>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXM=50000;
const int MAXN=10000;
int finish[MAXN+5];
vector<int> adjacent[MAXN+5];
vector<int> radjacent[MAXN+5];
bool visit[MAXN+5];
int finishtime;
int distribute[MAXN+5];
bool same[MAXN+5];
void dfs(int u)
{
int size;
int i;
visit[u]=true;
size=adjacent[u].size();
for(i=0;i<size;i++)
{
if(visit[adjacent[u][i]]==false)
{
visit[adjacent[u] [i]]=true;
dfs(adjacent[u][i]);
}
}
finishtime++;
finish[finishtime]=u;
}
void rdfs(int u,int num)
{
int i;
int size=radjacent[u].size();
visit[u]=true;
distribute[u ]=num;
for(i=0;i<size;i++)
{
if(visit[radjacent[u][i]]==false)
{
visit[radjacent[u][i]]=true;
distribute[radjacent[u][i]]=num;
rdfs(radjacent[u][i],num);
}
}
}
int main()
{
int N,M;
int i;
int j;
int from,to;
while(scanf("%d %d",&N,&M)!=EOF)
{
for(i=1;i<=M;i++)
{
scanf("%d %d",&from,&to);
adjacent[from].push_back(to);
radjacent[to].push_back(from);//图的转置
}
finishtime=0;
memset(visit,false,sizeof(visit));
for(i=1;i<=N;i++)
{
if(visit[i]==false)
{
dfs(i);
}
}//对图DFS,按结束时间进栈,先结束先进栈
memset(visit,false,sizeof(visit));
int num=1;
for(i=finishtime;i>=1;i--)
{
if(visit[finish[i]]==false)
{
rdfs(finish[i],num);
num++;
}
}//对转置的图DFS,按出栈顺序DFS
num--;
memset(same,0,sizeof(same));
for(i=1;i<=N;i++)
{
for(j=0;j<adjacent[i].size();j++)
{
if(distribute[i]!=distribute[adjacent[i][j]])
{
same[distribute[i]]=1;//标记出度不为0的块
}
}
}
int sub;
int same_sum=0;
for(i=1;i<=num;i++)
{
if(same[i]==0)
{
sub=i;
same_sum++;//统计出度为0的块的个数
}
}
int ans;
ans=0;
if(same_sum>1)
{
printf("0/n");
continue;
}//出度为0的块的数量超过1
else
{
for(i=1;i<=N;i++)
{
if(distribute[i]==sub)
{
ans++;
}
}//统计出度为0的块的节点的个数
printf("%d/n",ans);
}
}
return 0;
}
参考文献:北大2010summerschool的gw_connect.ppt
相关文章推荐
- POJ1236 强连通分支(strongly connected component _kosaraju algorithm)
- HDU 4635 —— Strongly connected——————【 强连通、最多加多少边仍不强连通】
- POJ 2186 -- Popular Cows (Strongly Connected Components)
- Strongly connected HDU - 4635 强连通
- [PTA] week12 4-10 Strongly Connected Components
- 6-10 Strongly Connected Components(30 分)
- Programming Question-4-Strongly Connected Components Problem through DFS
- D - Strongly Connected City
- 【CODEFORCES】 B. Strongly Connected City
- 【CF913F】Strongly Connected Tournament 概率神题
- Educational Codeforces Round 37 E. Connected Components?(920E)
- B. Strongly Connected City [强联通判断]
- Codeforces-292D:Connected Components(m个并查集)
- 图基本算法介绍:广度优先搜索、深度优先搜索、拓扑排序、强连通分支(算法篇)
- Educational Codeforces Round 37 E. Connected Components?(bfs)
- Number of Connected Components in an Undirected Graph 无向图中的连通区域的个数
- sicily connected components in undiected graph
- uva 12167(强连通分支)
- No323. Number of Connected Components in an Undirected Graph
- ural Mosaic(强连通分支)