二分图、割顶、桥都是图论中的重要知识点,很多题目在建模时都要用到。
因此二分图的判定算法和割顶与桥的判断算法都至关重要。
二分图的判定采用的是一个着色的方法,如果能将相邻的点涂上不同的颜色(颜色总数为2),那么这张图就是二分图了;
下面是相关代码:
int color[maxn];
vector<int>G[maxn];//邻接表
bool bipartite(int u)
{
for(int i = 0 ; i < G[u].size() ; i++)
{
int v = G[u][i];
if(color[u]==color[v])return false;
if(!color[v])
{
color[v] = 3 - color[u];
if(!bipartite(v))return false;
}
}
return true;
}
割顶和桥的判断算法同样有重要的意义,它的思想在双连通分量和强连通分量的求解中得到应用(割顶是双连通分量的分割依据,因为双连通分量是无向图的极大子图,因此不同的双连通分量的公共的至多有一个,如果有就是割顶)。
对于一个图的dfs树,如果一个点A的子节点B及其子孙可以连回的最早的祖先P不比A早(即P=A或P的遍历在A之后)的话,那么这个点是割顶,同理如果B的子孙后代最早可以连回B的话,边(A,B)是图的桥;
下面是核心代码:
int low[maxn],pre[maxn],dfs_clock = 0;
vector<int>G[maxn];
bool iscut[maxn],isbridge[maxn][maxn];
int n,m;
int dfs(int u,int fa)
{
int lowu = pre[u] = ++dfs_clock;
int child = 0;
for(int i = 0;i < G[u].size();i++)
{
int v = G[u][i];
if(!pre[v])
{
child++;
int lowv = dfs(v,u);
lowu = min(lowu,lowv);
if(lowu >= pre[u])
{
iscut[u] = true;
if(lowu > pre[u])
isbridge[u][v] = true;
}
}
else if(pre[v] < pre[u]&& v != fa)
lowu = min(lowu,pre[v]);
}
if(fa < 0&&child==1)
iscut[u] = false;
low[u] = lowu;
return lowu;
}
代码中可能有些判断显得冗余,但这样看起来思路更清晰。
其中用到的dfs_clock有一个好听的名字叫时间戳,是用来记录遍历顺序的。
之后博主会发一些关于上述代码的题解的,读者可以参考题目来理解。