Tarjan算法求连通图(代码含所需变量、初始化步骤):
#define MAXN 100000+5
//struct edge{
// int to;
// //int val; //若边有权值所需要的元素
//};
//int next[MAXN];
vector<int> G[MAXN];
int dfn[MAXN],low[MAXN];
bool instack[MAXN];
stack<int> s;
int timing; //时间戳
int color[MAXN]; //代表当前结点所属第几个scc
int colorcnt[MAXN]; //代表第某个scc有几个结点
int cnt; //scc个数
int V,E;
void init()
{
for(int i=0;i<=V;i++)
G[i].clear();
while(!s.empty())
s.pop();
mem(dfn,0);
mem(color,0);
mem(colorcnt,0);
mem(instack,false);
mem(low,0);
timing=cnt=0;
}
void tarjan(int u)
{
timing++;
dfn[u]=low[u]=timing;
s.push(u);
instack[u]=true;
for(int i=0;i<G[u].size();i++)
{
//int v=next[u];
int v=G[u][i];
if(dfn[v]==0)
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(instack[v])
{
low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u])
{
cnt++;
int temp;
do
{
//记录每个点属于哪个scc
temp=s.top();
s.pop();
instack[temp]=false;
color[temp]=cnt;
colorcnt[cnt]++;
}while(u!=temp);
}
}
Tarjan算法的调用:
int main()
{
while(cin >> V >> E && V+E)
{
init();
int a,b;
for(int i=0;i<E;i++)
{
cin >> a >> b;
G[a].push_back(b);
}
for(int i=1;i<=V;i++)
if(dfn[i]==0)
tarjan(i);
cout << cnt << endl;
}
return 0;
}
Tarjan算法求割点与求桥是基于无向图的!
Tarjan算法求割点(割点:去掉一个关键点、使得连通图不连通):
#define MAXN 105
//struct edge{
// int to;
// //int val; //如果有权值可以添加
//};
//int next[MAXN];
vector<int> G[MAXN];
int dfn[MAXN],low[MAXN];
bool instack[MAXN];
set<int> ans; //存储割点
stack<int> s;
int timing; //时间戳
int color[MAXN]; //代表当前结点所属第几个scc
int colornum[MAXN]; //代表第某个scc有几个结点
int cnt; //scc个数
int V,E;
void init()
{
for(int i=0;i<=V;i++)
G[i].clear();
ans.clear();
mem(dfn,0);
mem(color,0);
mem(colornum,0);
mem(instack,false);
mem(low,0);
timing=cnt=0;
}
割点
void tarjan_Point(int u,int rt)
{
++timing;
low[u]=dfn[u]=timing;
int child=0;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(dfn[v]==0)
{
child++;
tarjan_Point(v,rt);
low[u]=min(low[u],low[v]);
if(u!=rt && low[v]>=dfn[u]){
ans.insert(u);
}
}
low[u]=min(low[u],dfn[v]);
}
if(child>=2&&u==rt){
ans.insert(u);
}
}
求割点的调用:
int main()
{
cin >> V >> E;
for(int i=0;i<E;i++){
int a,b;
cin >> a >> b;
G[a].push_back(b);
G[b].push_back(a);
}
for(int i=1;i<=V;i++)
if(dfn[i]==0)
tarjan_Point(i,i);
cout << ans.size() << endl;
return 0;
}
Tarjan算法求桥(桥:在连通图中去掉一个边、使得连通图不连通)
struct edge{
int from,to;
};
edge qiao[MAXN];
void addpath(int a,int b){
qiao[top].from=min(a,b);
qiao[top++].to=max(a,b);
}
void tarjan_Edge(int u,int fa) {
dfn[u]=low[u]=++timing;
for(int i=0; i<G[u].size(); i++) {
int v=G[u][i];
if(v==fa)
continue;
if(!dfn[v]) {
tarjan_Edge(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u])
addpath(u,v);
}
else if(fa!=u){
low[u]=min(low[u],dfn[v]);
}
}
}
与割点的调用一模一样、不再贴出代码……
Tarjan算法相关题目:
HDU 1269 迷宫城堡 【传送门】(模板题)
UVA 315 Network 【传送门】(模板题)
UVA 796 Critical Link 【传送门】 (模板题)
洛谷 P3388 【传送门】 (模板题)
POJ 3180 The Cow Prom 【传送门】(模板题)
POJ 1236 Network of Schools 【传送门】
POJ 2186 Popular cows 【传送门】
未完待续……
POJ 2553 The bottom of a Graph
POJ 3177 Redundant Paths
POJ 3352 Road Construction
HDU 5934 Bomb
HDU 4612 Warm up