这一篇博客继续以一些OJ上的题目为载体,对图的连通性专题进行整理一下。会陆续的更新。。。
爱上大声地
一、相关定义
1、如果图G中任意两点可以相互到达。则称图G为强连通图。
2、如果图G不是强连通图,而它的子图G'是强连通图。那么称图G'为图G的强连通分量
求强连通分量主要以下三种算法:Kosaraju算法、Tarjan算法、Garbow算法。。。
二、例题
1、HDU 1269
1)使用Tarjan算法来解决
/*
* HDU_1269_2.cpp
*
* Created on: 2014年7月7日
* Author: pc
*/
#include <iostream>
#include <cstdio>
using namespace std;
const int maxm = 100010;//边的最大数目
const int maxn = 10005;//顶点的最大值
/**
* 链式前向星
*/
struct node{
int e;
int next;
}edge[maxm];
int head[maxn];
int n,m,k;
int low[maxn];//low[v]用与保存节点v邻接的未删除的节点u的low[u]和low[v]中的最小值
int dfn[maxn];//dfn[i]用来表示节点i的访问时间
int stack[maxn];//
int vis[maxn];//vis[i] = 1..表示节点i已经被访问过
int cnt,index,top;//cnt: 强连通分量的个数.top:用来维护栈中的数据
/**
* 添加一条边的操作。。。
* s: 边的起点
* e: 边的终点
*/
void add(int s,int e){
edge[k].e = e;
edge[k].next = head[s];
head[s] = k++;
}
/**
* 使用tarjan算法来求强连通分量的个数
* s: 表示要访问的节点
*/
void tarjan(int s){
//现骨干变量的初始化
low[s] = dfn[s] = ++index;
stack[++top] = s;
vis[s] = true;
//访问节点s邻接的所有未删除节点e
int i;
for(i = head[s] ; i != -1 ; i = edge[i].next){
int e = edge[i].e;
if(!dfn[e]){
tarjan(e);
low[s] = min(low[s],low[e]);
}else if(vis[e]){
low[s] = min(low[s],dfn[e]);
}
}
if(low[s] == dfn[s]){//表示当前节点就是一个强连通分量的根
cnt++;
int e;
do{
e = stack[top--];
vis[e] = false;
}while(s != e);
}
}
/**
* 完成初始化的相关操作..
*/
void init(){
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));//素有节点被访问的时间戳被初始化为0.表示还没有被访问
memset(vis,0,sizeof(vis));//一开始所有的节点被标记为未访问过...
cnt = 0;//cnt: 强连通分量的个数..
index = 0;
k = 0;//边的条数
top = -1;// 用来维护栈中的元素
}
int main(){
while(scanf("%d%d",&n,&m),n||m){
init();
int i;
for(i = 0 ; i < m ; ++i){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
}
for(i = 1 ; i <= n ; ++i){
if(!dfn[i]){
tarjan(i);
}
}
if(cnt == 1){
printf("Yes\n");
}else{
printf("No\n");
}
}
return 0;
}