【问题标题】:Efficient way to enumerate unique undirected paths枚举唯一无向路径的有效方法
【发布时间】:2020-12-06 05:57:55
【问题描述】:

给定一个节点子集 {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, 2, 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,2,3},我只想枚举(1-2-3)(1-3-2)(2-1-3)。其他三个排列 (2-3-1)(3-1-2)(3-2-1) 不应枚举,因为它们的相反顺序已经枚举。

【问题讨论】:

    标签: c++ algorithm boost graph


    【解决方案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  
    ...
    

    【讨论】:

    • 是的,我认为这比使用 unordered_set 和哈希更有效。虽然,还是N!将被枚举。您是否有任何只通过 N!/2 个案例的生成器?
    • 目前我看不到在最快的next_perm 算法或Heap's 算法中提前停止的简单方法,因为需要中间的“坏”变体来产生“好”变体。也许 STL 实现经过了良好的调整,并且优于快速制作的自己的实现,因此使用过滤可能不是最糟糕的变体。
    • 刚刚想通了 :) 会在几分钟内写出来。
    • 是的,我认为您的新编辑无需重复即可工作。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2012-09-02
    • 1970-01-01
    • 2020-10-10
    • 1970-01-01
    • 2013-09-23
    • 1970-01-01
    • 2016-09-25
    相关资源
    最近更新 更多