【问题标题】:Count unique quadrangles计算唯一的四边形
【发布时间】:2019-04-22 02:47:05
【问题描述】:

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

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

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

输出:一个 M×4 矩阵或数组列表。 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”开始):

案例一: 输入:

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

【问题讨论】:

  • 谢谢。我每次都故意“让”索引号在下一次迭代循环中变大——因为如果你不这样做,在某些图中,会一起找到重复的解决方案。然而,具有讽刺意味的是,这种方式无法处理我上面列出的 case-2,在这种情况下找不到解决方案。您可以为我列出的两种情况绘制图表,您就会明白这一点。
  • 好点。我会再尝试。对于每个顶点('start'),对于连接到'start'('neighbors')的每一对节点,找到一个连接到'neighbors'('end')的节点,其中'neighbors'和'的节点号end' 都大于 'start' 的节点号。
  • 我想出了一个不优雅的方法: 1. 找出所有(允许非唯一的)四边形序列,假设个数是N; 2. 对所有序列进行排序,O(N log4) = O(N) 3. 检测并删除重复序列,这一步可以应用很多技巧,例如将 [1,2,3,4] 映射到 1234 并对其进行哈希处理。但是,我仍然期待任何人都可以提供一个简单而优雅的算法。

标签: algorithm graph-algorithm computational-geometry combinatorics


【解决方案1】:

这是我更新的 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;

【讨论】:

    【解决方案2】:

    我有另一种方法来找到四边形。它使用了 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;
    }
    

    【讨论】:

    • 谢谢。我将阅读您的代码。我怀疑,是否会有任何“智能/优雅”的方式来实现我的目的,而无需使用任何特殊的数据结构,如堆栈、哈希表(或哈希图)或队列等。或者换句话说,避免“删除重复”过程。
    • 以下是我更新的 MATLAB 代码,可以运行(欢迎您测试我的代码,看看它是否在任何特殊图表上失败)。
    猜你喜欢
    • 2013-03-25
    • 1970-01-01
    • 2012-04-06
    • 2012-11-10
    • 2018-04-21
    • 2012-12-06
    • 2012-07-31
    • 2012-10-19
    • 2011-12-16
    相关资源
    最近更新 更多