Targin——图的割点
1.割边是什么(桥)
割边,也称为桥,即在一个无向连通图中,如果删除某条边后,图不再连通。
例如:
2.求割边的方法
1.可以一次删除每一条边,然后用DFS或BFS或并查集检查图是否连通,如果删除一条边后导致图不再连通,那么刚才删除的边就是割边。
2.还是采用上次实现的求割点的方法:
将low[v] >= num[u] 修改为 low[v] > num[u] 即可,下面解释一下原因:
low[v] >= num[u]表示节点v在不经过父节点u可以回到父节点。
low[v] > num[u]表示节点v在不经过父节点u不能回到父节点。
倘若节点v不能回到祖先,也没有另外一条路回到父亲,那么u->v就是割边。
2.1实现
#include <iostream>
#include <vector>
using namespace std;
/*
* 测试用例
6 6(顶点数和边数)
1 4
1 3
4 2
3 2
2 5
5 6
*/
class Cut_point
{
private:
int vertice = 0;//顶点数
int edge = 0;//边数
int root = 1;//记录根节点
//0行0列不存储信息,graph[i][j]表示节点i到节点j的权值为graph[i][j]
vector<vector<int>> graph;//存储图的信息
//在所有的数组中下标0均不存值
vector<int> num;//记录每个节点遍历的顺序(num[i] = j表示节点i是第j个被遍历的)
vector<int> low;//记录节点不经过父顶点回溯的最早的节点(low[i] = j表示节点i最早回到j节点)
int index = 0;//记录num中的值
public:
Cut_point(int x = 0, int y = 0) :vertice(x), edge(y)
{
graph.resize(vertice + 1);
for (int i = 0;i <= vertice; i++)
{
graph[i].resize(vertice + 1,0);
}
num.resize(vertice + 1, 0);
low.resize(vertice + 1, 0);
}
//图以及图相关的数据结构初始化
void Init_Graph(void)
{
int u = 0, v = 0;
for (int i = 0; i < edge; i++)
{
cin >> u >> v;
graph[u][v] = 1;
graph[v][u] = 1;//无向图的初始化,没有权重信息,初始化为1即可
}
}
void Cut_point_By_DFS(int curernt,int father)
{
int child = 0;//记录current节点的汉字总数
index++;//当前访问的顺序加1
num[curernt] = index;//表示current节点是在第index被访问的
low[curernt] = index;
for (int i = 1; i <= vertice; i++)
{
if (graph[curernt][i] == 1)
{
//节点i还没有被访问过
if (num[i] == 0)
{
Cut_point_By_DFS(i, curernt);//继续往下DFS
low[curernt] = min(low[curernt], low[i]); //更新current节点能够访问到的最早顶点的顺序
if (low[i] > num[curernt])//当前节点不是根节点,并且满足low[i] > num[current],则当前节点为割边
{
cout << curernt << " --> " << i << endl;
}
}
else if (i != father)
{
low[curernt] = min(low[curernt], num[i]);
}
}
}
}
};
int main()
{
int vertice = 0, edge = 0;//顶点数,边数
cout << "请输入顶点数和边数:" << endl;
cin >> vertice >> edge;
Cut_point point(vertice,edge);
cout << "请输入边的信息:" << endl;
point.Init_Graph();
cout << "割边为:";
point.Cut_point_By_DFS(1, 1);//从1号顶点开始进行DFS,并且认为1号顶点是根节点
return 0;
}