以下内容为个人理解,有错误地方还请指出。
求割点
点u是割点的充分条件:
1. 如果u是dfs树的根,则u至少有两个子女。
2. 如果u不是dfs树的根,则它至少有一个子女w,从w出发,不可能通过和w、w的子孙相连的回边到达u的祖先。
u是割点的充要条件是:u或则是具有两个以上子女的深度优先生成树的根,或则虽然不是根,但它有一个子女w,使得low[w]>=dfn[u]。
求割边
有两种判断方法:
1. 当点u的子女v满足low[v]>dfn[u] 时,(u,v),(v,u)是一条割边;
2. 当无向图G中u,v相连,但是low[u]!=low[v]时,(u,v),(v,u)是一条割边。(因为同一边双连通分量的点,low值相同,详细可参考缩点)
//tarjan算法模板
vector<int>head[maxn];//邻接表
tarjan_dfs(int rt,int father)//father为rt的父节点
{
int son=0;//rt的子女数
dfn[rt]=low[rt]=dep_tmp++;
vis[rt]=true;
for(int i=0,len=head[rt].size();i<len;++i)
{
int v=head[rt][i];
if(!vis[v])
{
son++;
tarjan_dfs(v,rt);
low[rt]=min(low[rt],low[v]);
}
else if(v!=father)//不要原路返回
{
low[rt]=min(low[rt],dfn[v]);
}
if( (rt!=root && low[v]>=dfn[rt] )|| (rt==root && son>1) )
{
cut[rt]=true;//标记割点
}
if( low[v]>dfn[rt]
{
cut_edge[rt][v]=true;//标记割边
cut_edge[v][rt]=true;
}
}
}
Poj1523 SPF
给定一个连通网络(无向图),网络的结点数<=1000,求出这个网络的所有割点编号,并求出若删去其中一个割点k后,对应的,原网络会被分割为多少个连通分量
class POJ_1523
{
protected:
bool _map[maxn][maxn];
int low[maxn];//特点
int dfn[maxn];//点的dfs序号
bool cut[maxn];//标记是否为割点
bool vis[maxn];
int dep_tmp;
int root;//dfs起点 这里我设置为最小的点
int size;//最大点的标号+1
int I;
public:
int input();
bool solve();
void initial();
void dfs_net(int rt);
void tarjan_dfs(int rt,int father);
POJ_1523() {
I=1;
while(solve());
}
};
void POJ_1523::initial()
{
mem(_map); mem(low); mem(dfn); mem(vis); mem(cut);
dep_tmp=1;
}
int POJ_1523::input()
{
int x,y,num=0;
root=maxn; size=0;
while(scanf("%d",&x)&&x)
{
num++;
scanf("%d",&y);
root=min(root,min(x,y));
size=max(size,max(x+1,y+1));
_map[x][y]=_map[y][x]= true;
}
return num;
}
void POJ_1523::tarjan_dfs(int rt,int father)
{
int son=0;
dfn[rt]=low[rt]=dep_tmp++;
vis[rt]=true;
for(int i=1;i<size;++i)
{
if(_map[rt][i])
{
if(!vis[i])
{
son++;
tarjan_dfs(i,rt);
low[rt]=min(low[rt],low[i]);
}
else if(i!=father)//如果不是父节点,那就是一条回边
low[rt]=min(low[rt],dfn[i]);
if( (rt==root && son>1) || (rt!=root && low[i]>=dfn[rt]) )
cut[rt]=true;
}
}
}
bool POJ_1523::solve()
{
initial();
if(!input())
return false;
int i;
for(i=1;i<size;++i)
{
if(!vis[i])//只进一次 因为图是联通的
tarjan_dfs(i,i);
}
if(I!=1)
printf("\n");
printf("Network #%d\n",I++);
bool flag=false;
for(i=root;i<size;++i)
{
if(cut[i])
{
mem(vis);
vis[i]=true;
int j,subnet_num=0;
for(j=root;j<size;++j)
{
if(_map[j][i]&&!vis[j])
{
subnet_num++;
dfs_net(j);
}
}
printf(" SPF node %d leaves %d subnets\n",i,subnet_num);
flag=true;
}
}
if(!flag)
printf(" No SPF nodes\n");
return true;
}
void POJ_1523::dfs_net(int rt)
{
vis[rt]=true;
int i;
for(i=root;i<size;++i)
{
if(!vis[i]&&_map[i][rt])
dfs_net(i);
}
}
int main() { POJ_1523 final_ans; }