一.割点与割边
题目链接 http://hihocoder.com/problemset/problem/1183
割点:
- x不是根:只要有low[v[x]]>=low[x] 说明v[x]不通过x没法回到x来时的地方,所以x为割点
- x是根:x有两个及以上的直接儿子(注意这里的儿子是放在!dfn中的,不然就是x的儿子的儿子)即可
代码如下:注意点都写注释里了呀!
void tarjan(int x,int fa)
{
dfn[x]=low[x]=++iindex;int child=0,flag=0;
for(int i=0;i<v[x].size();i++)
{
if(!dfn[v[x][i]])
{
child++;//注意child的位置!
tarjan(v[x][i],x);
low[x]=min(low[x],low[v[x][i]]);
if(low[v[x][i]]>=dfn[x]) flag=1;//割点条件
}
else if(v[x][i]!=fa) low[x]=min(low[x],dfn[v[x][i]]);//这里要判断v[x][i]不是x的父亲哦
}
if(x==root&&child>=2) cut[x]=1;
if(x!=root&&flag) cut[x]=1;
if(cut[x]) tot++;
}
割边:
- 与割点的区别:如果v[x]连爸爸都找不到了,那他到爸爸的那条边就是连接他们的唯一路径,就是桥(割边)
所以这里改成:low[v[x]]>dfn[x]
别的都一样啊,不过不用判根
void tarjan2(int x,int fa)
{
dfn[x]=low[x]=++iindex;
for(int i=0;i<v[x].size();i++)
{
if(!dfn[v[x][i]])
{
tarjan2(v[x][i],x);
low[x]=min(low[x],low[v[x][i]]);
if(low[v[x][i]]>dfn[x])
{
int t1=min(v[x][i],x);int t2=max(v[x][i],x);
ans.push_back(make_pair(t1,t2));
}
}
else if(v[x][i]!=fa) low[x]=min(low[x],dfn[v[x][i]]);
}
}
二.边双
题目链接 http://hihocoder.com/problemset/problem/1184
1.就是做一遍和刚才求割点差不多的程序,但为了存点,我们引入了stack
2.stack中到x的点都属于一个联通分量
代码如下:
void tarjan(int x,int fa)
{
dfn[x]=low[x]=++iindex;s.push(x);vis[x]=1;
for(int i=0;i<v[x].size();i++)
{
if(!dfn[v[x][i]])
{
tarjan(v[x][i],x);
low[x]=min(low[x],low[v[x][i]]);
}
else if(v[x][i]!=fa) low[x]=min(low[x],dfn[v[x][i]]);
}
if(low[x]==dfn[x])
{
tot++;int minv=1e9;
while(1)
{
int tmp=s.top();minv=min(minv,tmp);
belong[tmp]=tot;
s.pop();
if(tmp==x) break;
}
num[tot]=minv;
}
}
三.强联通分量
http://hihocoder.com/problemset/problem/1185
1.与边双的思路很像,但它是有向图
2.所以引入vis的数组以判断这个点在不在stack里。(而边双只是判断他是不是father)
void tarjan(int x,int fa)
{
dfn[x]=low[x]=++iindex;vis[x]=1;s.push(x);
for(int i=0;i<v[x].size();i++)
{
if(!dfn[v[x][i]])
{
tarjan(v[x][i],x);
low[x]=min(low[x],low[v[x][i]]);
}
else if(vis[v[x][i]])//这里和边双不一样
{
low[x]=min(dfn[v[x][i]],low[x]);
}
}
if(dfn[x]==low[x])
{
while(1)
{
int tmp=s.top();s.pop();
vis[tmp]=0;if(tmp!=x) w[x]+=w[tmp];
belong[tmp]=x;
if(tmp==x) break;
}
}
}
应用
1.缩点:https://www.luogu.org/problemnew/show/P3387
强联通分量的基本应用 本质:有向有环图->有向无环图DAG
2.抢掠计划:https://www.luogu.org/problemnew/show/P3627
求最长路径,一个基本应用呐
注意topo和dfs的应用
有出发点用dfs,否则的用topo
3.信息传递:https://www.luogu.org/problemnew/show/P2661
求最小环,用的强联通分量。不过这个用dfs更清晰简单 vis:0,1,2