Подсчитайте уникальные четырехугольники - PullRequest
0 голосов
/ 19 ноября 2018

Дан плоский ненаправленный граф с n точками, помеченными целым числом [1,2, .. n]

Задача состоит в том, чтобы найти все уникальные четырехугольники, под «уникальными», мы имеем в виду: если два четырехугольника имеют все четыре точки одинаковые, но различен только относительный порядок, то эти два считаются «одинаковыми» четырехугольник. Например, [1,2,3,4] и [1,3,2,4] - это один и тот же четырехугольник.

Ввод: график может быть сохранен в любом формате, который вы предпочитаете. Здесь мы используем смежную матрицу (для неориентированного графа каждое физическое ребро вводится один раз в следующем описании), первые два числа в 1-й строке - это номер вершины и номер ребра соответственно. Затем следующие строки вводят каждое ребро каждый раз.

Вывод: матрица 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»):

Case-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

Case-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 голосов
/ 20 ноября 2018

Вот мой обновленный код 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;
0 голосов
/ 20 ноября 2018

У меня есть другой подход, чтобы найти четырехугольники. Он использует концепцию DFS. Пройдите по графику для всех узлов, чтобы найти четырехугольники для определенной глубины. Чтобы удалить дубликаты, отсортируйте четырехугольники, затем удалите четырехугольники или используйте хэш-таблицу. Моя реализация на С ++ приведена ниже:

#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;
}
...