枚举唯一的无向路径的有效方法

问题描述

给定节点{1,2,...,N}的子集,是否有任何STLboost函数在所有节点上返回唯一的无向游览?

std::next_permutation()给出了所有N!定向导览,其中1-2-...-NN-N-1-...-2-1不同。

但是,在这种情况下,我既不想要它们,也只想要其中一个。本质上,我只想列举其中的N! / 2个游览。

以下使用std::next_permutation()unordered_set代码有效,但是还有效率更高的吗?以下代码从本质上生成了所有N!定向的游览,并在对unordered_set()进行了检查之后将其中的一半丢弃。

#include <vector>
#include <unordered_set>
#include <algorithm>
#include <boost/functional/hash.hpp>

template <typename T,typename U> bool unorderedset_val_there_already_add_if_not(std::unordered_set<T,U>& uos,T& val) {
    if (uos.find(val) != uos.end())
        return true;//val already there
    uos.insert(val);
    return false;//Value is new.
}

int main() {
    std::vector<int> sequence{ 1,3};
    std::unordered_set<std::vector<int>,boost::hash<std::vector<int>>> uos;

    do {
        printf("Considering ");
        for (std::size_t i = 0; i < sequence.size(); i++)
            printf("%d ",sequence[i]);
        printf("\n");
        std::vector<int> rev_sequence = sequence;
        std::reverse(rev_sequence.begin(),rev_sequence.end());
        if (unorderedset_val_there_already_add_if_not(uos,sequence) || unorderedset_val_there_already_add_if_not(uos,rev_sequence)) {
            printf("Already there by itself or its reverse.\n");
        }
        else {
            printf("Sequence and its reverse are new.\n");
        }
    } while (std::next_permutation(sequence.begin(),sequence.end()));
    getchar();
}

也就是说,给定{1,3},我只想列举(1-2-3)(1-3-2)(2-1-3)。其他三个排列(2-3-1)(3-1-2)(3-2-1)不应枚举,因为它们的反向顺序已被枚举。

解决方法

如果您想继续使用next_permutation而不是使用自己的生成器例程,最简单的方法是在某些条件下过滤掉一半排列。

非常简单:最后一个元素应大于第一个元素。

#include <vector>
#include <algorithm>
#include "stdio.h"

int main() {
    std::vector<int> sequence{ 1,2,3,4};
    
    do {
        if (sequence[sequence.size()-1] > sequence[0]) {
            for (std::size_t i = 0; i < sequence.size(); i++)
                printf("%d ",sequence[i]);
            printf("\n");
        }        
    } while (std::next_permutation(sequence.begin(),sequence.end()));
    getchar();
}

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

可能的实现:

Generate all pairs (start; end)     where start < end  
  Generate all permutations of `n-2` values without start and end  
      For every permutation make {start,permutation..,end}

1 ... 2 + permutations of {3,4}
1 3 4 2
1 4 3 2  
1 ... 3 + permutations of {2,4}
1 2 4 3
1 4 2 3  
...
3 ... 4 + permutations of {1,2}
3 1 2 4
3 2 1 4  
...