求割点算法及其MATLAB实现

摘要

在一个无向图中,如果有一个顶点集合,删除这个顶点集合以及这个集合中所有顶点相关联的边以后,图的连通分量增多,就称这个点集为割点集合。
如果某个割点集合只含有一个顶点X(也即{X}是一个割点集合),那么X称为一个割点
(来自百度百科)

算法思想

其中,下述中的k(v)称为顶点v的DFS编码;f(v)称为顶点的父,v称为f(v)的子,且以f(v)为起始点、v为终点的有向边称为父子边。
先给出有关割点的两个定理
1.在深度优先搜索过程中,若e = uv 是父子边,且k(u)>1,l(v) >= k(u),则u是割点。
2.若r是深度优先搜索过程中生成的树的根,则r是图G割点的充分必要条件是至少有两条以r为尾的父子边
那么首先利用深度搜索算法求出k(u)和边的访问顺序矩阵W;然后利用l(v)的定义,求出每个顶点的l(v)值,再根据以上两个定理进行是否割点的判断;最后输出割点。

程序的参数说明

G为图的邻接矩阵
nc表示所求出的割点的集合

MATLAB实现

function nc = ncutf(G)
n = size(G,1);
if n >= 3
    a = sum(G);
    b = sum(a == 2);
    if b == n
        fprintf('本图为圈,无割点。');
    else
    %深度优先搜索
    [W,k] = DFS3(G);
    nc = isncf(W,k);
    n = size(G,1);
    for i = 1:n
        for j = 1:n
            if W(i,j) > 1
                if k(i) > k(j)
                    G(i,j) = 2;
                else
                    G(i,j) = 3;
                end
            end
        end
    end

    for i = 1:n
        f1 = find(G(i,:) == 2);
        f2 = find(G(i,:) == 3);
        f = union(f1,f2);
        l(i) = min([k(f) k(i)]);
    end

    for i = 1:n
        for j = 1:n
            if G(i,j) == 3 & k(i) > 1 & l(j) >= k(i)
                nc = union(i,nc);
            end
        end
    end
    end
else
        fprintf('图的顶点小于3,不存在割点。')
end


%在求割点的算法中,对图进行深度搜索
function [W k f] = DFS3(G)
n = size(G,1);
W = G;
v = 1;
k = zeros(1,n);
f = zeros(1,n);
b = sum(sum(W == 1));
c = sum(k == 0);
d = 1;
if b == 0 & c == 0 & v == 1
    d = 0;
end
k(1) = 1;
j = 2;
l = 2;

while d
    a = find(W(v,:) == 1);
    if isempty(a) & f(v) ~= 0
        W(v,f(v)) = l;
        l = l + 1;
        v = f(v);
    else
        for i = 1:length(a)
            if k(a(i)) == 0
                k(a(i)) = j;
                j = j + 1;
                W(v,a(i)) = l;
                l = l + 1;
                f(a(i)) = v;
                v = a(i);
                break;
            elseif k(a(i)) ~= 0
                W(v,a(i)) = l;
                l = l + 1;
            end
        end
    end
    b = sum(sum(W));
    c = sum(k == 0);
    if c == 0 & v == 1
        d = 0;
    end
end
W;


%在求割点的集合的算法中,判断起始点是否是割点
function nc = isncf(W,k)
nc = [];
T = zeros(size(W));
n = size(W,1);
a = find(W ~= 0);
for i = 1:length(a)
    d(i) = W(a(i));
    if a(i) / n > floor(a(i) / n)
        t(i) = floor(a(i) / n) + 1;
    else
        t(i) = floor(a(i) / n);
    end
    t1(i) = mod(a(i),n);
    if t1(i) == 0
        t1(i) = n;
    end
end
    [~,c] = sort(d);
    p = [1];
    pc = 0;
    for i = 1:length(a)
        if k(t1(c(i))) < k(t(c(i)))
            p = union(p,t(c(i)));
            T(t1(c(i)),t(c(i))) = 3;
        end
        if pc == 0
            tc = isempty(setdiff([1:n],p));
            if tc
                t0 = sum(T(1,:) == 3);
                if t0 >= 2
                    nc = union(nc,1);
                end
                break;
            end
        end
    end

测试

测试用例:G =

 0     1     0     0
 1     0     0     1
 0     0     0     1
 0     1     1     0

测试结果:nc =

 2     4

你可能感兴趣的:(图论,算法)