计算独特的四边形

时间:2018-11-19 17:25:06

标签: algorithm graph-algorithm computational-geometry combinatorics

给出一个平面n向无向图,其中n个点用整数[1,2,.. n]标记

任务是通过“唯一”找到所有唯一的四边形,我们的意思是:如果两个四边形的所有四个点都相同,但是相对顺序不同,则将这两个视为“相同”四边形。例如,[1,2,3,4]和[1,3,2,4]是相同的四边形。

输入:可以按您喜欢的任何格式存储图形。这里我们使用相邻矩阵(对于无向图,在下面的描述中,每个物理边均输入一次),第一行中的前两个数字分别是顶点数和边数。然后,以下各行每次都输入每个边缘。

输出:4乘M矩阵或数组列表。 M是您找到的最后一个唯一的四边形计数。

在以下五个点的无向完整图中:

5  10
1    4
1    2
1    3
1    5
2    3
2    4
2    5
3    4
3    5
4    5

只有五个唯一的四边形(忽略顶点序列的相对顺序):

 1     2     3     4
 1     2     3     5
 1     2     4     5
 1     3     4     5
 2     3     4     5

我现在没有完美的解决方案。

以下MATLAB解决方案只能为Case-1找到每个唯一的四边形,但在Case-2中失败,即找不到四边形。

%% Count Quadrangles

clc;

v = vertex(:,1);
t = vertex(:,2);
G = zeros( max(max(v),max(t)));
n = length(G);

% For muilt-edge graph , Build the matrix for graph:
for i = 1:length(v)
    G(v(i), t(i)) = G(v(i), t(i)) + 1; 
    G(t(i), v(i)) = G(v(i), t(i)); 
end
issymmetric(G)
max(max(G))

% For single edge graph, Build the matrix for graph:
% G(sub2ind(size(G),v, t))=1;
% G(sub2ind(size(G),t, v))=1; % fill the symmetric position

tic 

quad_cnt = 0; 
% G_ = graph(G);
quad_points = [];
%% O(N^3)
for i = 1:n
    for j = i+1:n
        if (j==i || G(i,j)==0)
            continue;
        end

        for k = j+1:n
            if ( k==i || k==j || (G(k,i)==0 && G(k,j) == 0) )
                continue;
            end  

            for p = k+1:n  

                if ( p==i || p==j || p==k || G(p,i)==0 || G(p,k) == 0)
                    continue;
                end 

                % otherwise, a quadrangle is ofund
                quad_cnt = quad_cnt+1; 
                % save the vertices
                quad_points(quad_cnt,:) = [i,j,k,p];
            end

        end                  
    end   
end
toc
% 0.1571 sec

quad_cnt

% output each triangle:
quad_points

%% O(deg*(V^2))

测试用例 通过使用顶点索引进行边输入(注意:从“ 1”开始而不是“ 0”):

情况1: 输入:

5   10
1   4
1   2
1   3
1   5
2   3
2   4
2   5
3   4
3   5
4   5

输出:

 1     2     3     4
 1     2     3     5
 1     2     4     5
 1     3     4     5
 2     3     4     5

情况2: 输入:

8    8
1    3
2    3
1    4
2    4
1    8
2    5
3    6
4    7

输出:

1 2 3 4

2 个答案:

答案 0 :(得分:0)

我还有另一种方法来查找四边形。它使用DFS的概念。遍历所有节点的图以找到特定深度的四边形。要删除重复项,请对四边形进行排序,然后删除四边形或使用哈希表。我的c ++实现如下:

#include<bits/stdc++.h>

using namespace std;

// if Edge[a][b] = 1, then there is an edge between node 'a' and 'b'
int Edge[100][100] = {0};

// to keep the list of quadrangles
// here 'set' is a data structure that keep unique elements
set< vector<int> > quadrangles;

// forbiddenNode[n] = 1, if this node 'n' is forbidden to visit
// forbiddenNode[n] = 0, if this node 'n' is not forbidden to visit
int forbiddenNode[100]={0};

// taken[n] = 1, if this node 'n' is taken in current Quadrangles
// taken[n] = 0, if this node 'n' is not taken in current Quadrangles
int taken[1000]={0};

void AddQuadrangle(vector<int> q) {
    sort(q.begin(), q.end());
    quadrangles.insert(q);
}

void findQuadrangles(int curNode, int depth, vector<int> &curQuadrangles, int numOfNodes) {
    if(depth == 0) {
        if( Edge[curNode][curQuadrangles[0]] == 1) {
            // found a quadrangle
            AddQuadrangle(curQuadrangles);
        }
    }
    for(int i = 1; i <= numOfNodes; i++) {
        if(forbiddenNode[i] == 0 && taken[i] == 0 && Edge[curNode][i] == 1) {
            // take this node
            taken[i] = 1;
            // add this node to curQuadrangles in the back
            curQuadrangles.push_back(i);

            findQuadrangles(i, depth - 1, curQuadrangles, numOfNodes);

            // undo take this node
            taken[i] = 0;
            // remove this node to curQuadrangles from the back
            curQuadrangles.pop_back();

        }
    }
}

int main() {
    int numOfNodes, numOfEdge;

    // take input for number of nodes, edges
    scanf("%d %d", &numOfNodes, &numOfEdge);

    // take input for edges
    for(int i=0; i < numOfEdge; i++) {
        int x, y;
        scanf("%d %d",&x, &y);
        Edge[x][y] = 1;
        Edge[y][x] = 1;
    }

    for(int i = 1; i <= numOfNodes; i++) {
        vector<int> curQuadrangle;
        curQuadrangle.push_back(i);
        taken[i] = 1;

        findQuadrangles(i, 3, curQuadrangle, numOfNodes);

        // set this node as forbidden to include in any quadrangle
        forbiddenNode[i];
    }

    // print quadrangles
    for( set<vector<int> >::iterator it = quadrangles.begin(); it != quadrangles.end(); it++) {
        vector<int> q = *it;
        printf("%d %d %d %d\n",q[0], q[1], q[2], q[3]);
    }

    return 0;
}

答案 1 :(得分:0)

这是我更新的MATLAB代码,可以正常工作(欢迎您测试我的代码,看看它在任何特殊图形上是否失败):

clc;

v = vertex(:,1);
t = vertex(:,2);
G = zeros( max(max(v),max(t)));
n = length(G);

% For multi-edge graph , Build the matrix for graph:
for i = 1:length(v)
    G(v(i), t(i)) = G(v(i), t(i)) + 1; 
    G(t(i), v(i)) = G(v(i), t(i)); % comment here is input is bi-directional
end

quad_cnt = 0;  
quad_points = [];

for i = 1:n
    for j = i+1:n
        if (j==i || G(j,i)==0)
            continue;
        end

        for k = i+1:n
            if ( k==i || k==j || (G(k,i)==0 && G(k,j)==0))
                continue;
            end  


            if (G(k,i)~=0 && G(k,j)~=0)
                 for p = i+1:n 
                    if ( p==i || p==j || p==k) 
                          continue;
                    end

                    if (G(p,i)~=0 && G(p,j)~=0)||(G(p,i)~=0 && G(p,k)~=0)||(G(p,j)~=0 && G(p,k)~=0)
                        quad_cnt = quad_cnt+1; 
                        quad_points(quad_cnt,:) = [i,j,k,p];
                    end                                         
                 end   
            end

            if (G(k,i)==0 && G(k,j)~=0)
                for p = i+1:n 
                    if (p==i || p==j || p==k || G(p,k)==0 || G(p,i) == 0)
                          continue;
                    end 
                    quad_cnt = quad_cnt+1; 
                    quad_points(quad_cnt,:) = [i,j,k,p];  
                 end

            end

            if (G(k,i)~=0 && G(k,j)==0)
               for p = i+1:n 
                   if ( p==i || p==j || p==k || G(p,j)==0 || G(p,k) == 0)
                         continue;
                   end 
                   quad_cnt = quad_cnt+1; 
                   quad_points(quad_cnt,:) = [i,j,k,p];   
               end                
            end         
        end                  
    end   
end

% quad_cnt

% Remove repeat
% 1) sort
hash = [];
Base = max(max(v),max(t))+ 1;
for i =1: quad_cnt
    temp = sort(quad_points(i,:));
    quad_points(i,:) = temp;
    hash(i) = quad_points(i,1)*Base^3 + quad_points(i,2)*Base^2 + quad_points(i,3)*Base + quad_points(i,4);
end

% 2)  remove repeats
[C, ~, ~]  = unique(hash);

quad_cnt = length(C);
quad_cnt

quad_points = [];

for i = 1: quad_cnt
    num = C(i);
    digit = [];
    for k = 1:4
        digit(k) = mod(num, Base);
        num = fix(num/Base); % or use "floor()"
    end
    quad_points(i,:) = digit;
end 


% output each quadrangle:
quad_points;