//输入图的邻接矩阵,节点编号0~n
void doDFS(const vector<vector<int> >& G,int v,int currDfs,bool isRoot,vector<int>& low,vector<int>& dfs,vector<int>& articulation);
void calcArticulation(const vector<vector<int> >& G,vector<int>& articulation)
{
int v = 0;
int currDfs=0;
vector<int> low(G.size(),-1), dfs(G.size(),-1);
doDFS(G,v,currDfs,true,low,dfs,articulation);
}
//G:邻接矩阵, v当前节点,currdfs当前的dfs编号,isroot指示v是否是dfs树的根节点,
//low记录所有节点的最早祖先,dfs记录所有节点的dfs序号,articulation存放求得的割点
void doDFS(const vector<vector<int> >& G,int v,int currDfs,bool isRoot,vector<int>& low,vector<int>& dfs,vector<int>& articulation)
{
dfs[v] = currDfs;
low[v] = currDfs;
bool isArticulation=false;
int child=0; //记录节点v的dfs子树个数
for(size_t i=0; i < G[v].size(); ++i)
{
if(G[v][i]==0){continue;}
int next = i;
if(dfs[next] == -1){
child++;
doDFS(G,next,currDfs+1,false,low,dfs,articulation);
if(low[next] >= dfs[v]){//子树没有回溯到v的祖先,v是割点
isArticulation = true;
}
else{//子树连通祖先,需要更新low[v]
low[v] = low[next] < low[v] ? low[next]:low[v];
}
}
else{
//注意判断next小于low[v],因为low[v]可能被循环反复更新
low[v] = dfs[next] < low[v] ? dfs[next] : low[v];
}
}
if(isArticulation==true)
{
//如果是DFS树根,还需要满足额外条件
if(isRoot==true) {
if(child > 1){
articulation.push_back(v);
}
}
else{
articulation.push_back(v);
}
}
}
static void test(const vector<vector<int> >& G)
{
vector<int> articulation;
calcArticulation(G,articulation);
for(size_t i=0; i < articulation.size();++i){
printf("%d,",articulation[i]);
}
printf("\n");
}
// ---- 0
// | / \
// | 1 4
// | / \
// 2 3
static void test1()
{
int t[5][5]={
{0,1,1,0,1},
{1,0,1,1,0},
{1,1,0,0,0},
{0,1,0,0,0},
{1,0,0,0,0}
};
vector<vector<int> > G(5);
for(int i=0; i < 5 ;++i){
G[i].assign(t[i],t[i]+5);
}
test(G);
}
// 0
// / \
// 1 4
// / \
// 2 3
static void test2()
{
int t[5][5]={
{0,1,0,0,1},
{1,0,1,1,0},
{0,1,0,0,0},
{0,1,0,0,0},
{1,0,0,0,0}
};
vector<vector<int> > G(5);
for(int i=0; i < 5 ;++i){
G[i].assign(t[i],t[i]+5);
}
test(G);
}
// 0
// / \
// 1 4
// / \
// 2 3
// \
// 5
static void test3()
{
int t[6][6]={
{0,1,0,0,1,0},
{1,0,1,1,0,0},
{0,1,0,0,0,0},
{0,1,0,0,0,1},
{1,0,0,0,0,0},
{0,0,0,1,0,0}
};
vector<vector<int> > G(6);
for(int i=0; i < 6 ;++i){
G[i].assign(t[i],t[i]+6);
}
test(G);
}
// 0
// / \
// 1----3
// /
// 2
static void test4()
{
int t[4][4]={
{0,1,0,1},
{1,0,1,1},
{0,1,0,0},
{1,1,0,0}
};
vector<vector<int> > G(4);
for(int i=0; i < 4 ;++i){
G[i].assign(t[i],t[i]+4);
}
test(G);
}
// 0
// /
// 1
// / \
// 2 3
static void test5()
{
int t[4][4]={
{0,1,0,0},
{1,0,1,1},
{0,1,0,0},
{0,1,0,0}
};
vector<vector<int> > G(4);
for(int i=0; i < 4 ;++i){
G[i].assign(t[i],t[i]+4);
}
test(G);
}
//双连通图,没有割点
// -----0
// | / |
// | 1 |
// | / \ |
// 2 3
static void test6()
{
int t[4][4]={
{0,1,1,1},
{1,0,1,1},
{1,1,0,0},
{1,1,0,0}
};
vector<vector<int> > G(4);
for(int i=0; i < 4 ;++i){
G[i].assign(t[i],t[i]+4);
}
test(G);
}
static void test7()
{
int t[2][2]={
{0,1},
{1,0}
};
vector<vector<int> > G(2);
for(int i=0; i <2 ;++i){
G[i].assign(t[i],t[i]+2);
}
test(G);
}
// 0
// / \
// 1 4
// / \
// 2 3
// | \
// ---- 5
static void test8()
{
int t[6][6]={
{0,1,0,0,1,0},
{1,0,1,1,0,1},
{0,1,0,0,0,0},
{0,1,0,0,0,1},
{1,0,0,0,0,0},
{0,1,0,1,0,0}
};
vector<vector<int> > G(6);
for(int i=0; i < 6 ;++i){
G[i].assign(t[i],t[i]+6);
}
test(G);
}
void testArticulation()
{
test1();
test2();
test3();
test4();
test5();
test6();
test7();
test8();
}