更智能地循环排列

时间:2012-05-28 22:59:14

标签: c++ algorithm

我有一个3乘3的布尔值网格,我对我可以拥有三个“活”单元格的方式感兴趣(根据我的计算,有56个排列)。旋转对称并不重要,但活细胞彼此难以区分。

假设我在网格中相对于质心索引值:

-------------------
|-1,-1| 0,-1| 1,-1|
-------------------
|-1,0 |     | 1,0 |
-------------------
|-1,1 | 0,1 | 1,1 |
-------------------

有一个很好的循环可以用来计算56个排列吗? (我刚刚完成了所有输入,我很想知道我是否可以稍微聪明一些)。

我正在使用C ++,但如果很清楚,基本算法在任何语言或伪语言中都会很精彩。

4 个答案:

答案 0 :(得分:4)

您可以使用next_permutation

例如,假设字符串下面x中的每个字符表示网格中的一个单元格(质心单元格除外)从左上角开始并向右下方开始。您可以运行此代码以查找所有可能的排列,并且在循环内,字符串x将表示可能的排列,其中1是活动单元格,0是死亡单元格。

int main() {
  string x = "00000111";
  int cnt = 0;
  do {
    ++cnt;

    // do something useful with this configuration...

  } while(next_permutation(x.begin(),x.end()));
  cout<<cnt<<endl;
  return 0;
}

答案 1 :(得分:1)

从维基百科尝试this procedure

  

以下算法在给定排列后按字典顺序生成下一个排列。它就地改变了给定的排列。

     
      
  1. 找到最大的索引k,使得a [k]&lt; a [k + 1]。如果不存在这样的索引,则排列是最后的排列。
  2.   
  3. 找到最大的索引l,使得a [k]&lt;一个[1]。由于k + 1是这样的指数,因此l被很好地定义并且满足k <1。升。
  4.   
  5. 用[l]交换[k]。
  6.   
  7. 将序列从[k + 1]反转到最后一个元素a [n]。
  8.   

答案 2 :(得分:0)

你可以使用这种方法:

假设您使用数组表示网格,其中元素为

[(-1,-1), (0,-1),(1,-1)...] 

等等,你基本上把元素放在第一行,然后是第二行,然后是第三行。

所以现在,你只需要拿走你拥有的所有可用数字,也就是说:

[1,1,1,0,0,0,0,0,0]

正如你所说,你只需要3个活细胞。

现在我们决定了不同的字符串意味着,你可以简单地选择一个执行排列的代码,就像这个链接上的xcellnt一样How To Generate Permutation In C? 这完全符合你的要求,或者算法库中的std :: next_permutation之类的任何等效代码。

答案 3 :(得分:0)

您更喜欢“更智能”循环或“ saner ”吗?

//c++ --std=c++11 test.cc

#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <algorithm>
#include <utility>

using std::string;
using std::list;
using std::vector;

const string show[8] = { "(-1,-1)","( 0,-1)","( 1,-1)"
                       , "(-1, 0)",          "( 1, 0)"
                       , "(-1, 1)","( 0, 1)","( 1, 1)"
                       };

auto permutations_of_living_cells =
    [] (int number_of_living_cells) -> list<vector<string>>
    {
    typedef list<vector<string>> (*recT)( void*
                                        , int
                                        , int
                                        , vector<string> &&
                                        , list<vector<string>> &&
                                        );
    recT rec = []( void*r
                 , int n
                 , int i
                 , vector<string> && prefix
                 , list<vector<string>> && l
                 ) -> list<vector<string>>
        {
        if( n==0 )
            {
            l.push_back(std::move(prefix));
            return std::move(l);
            }
        if( i>8-n ) return std::move(l);
        vector<string> psi(prefix);
        psi.push_back(show[i]);
        return  ((recT)r)(r,n  ,i+1,std::move(prefix),
                ((recT)r)(r,n-1,i+1,std::move(psi   ),
                    std::move(l)
                )
                );
        };
    return rec( (void*)rec
              , number_of_living_cells
              , 0
              , vector<string>()
              , list<vector<string>>()
              );
};

template<class T>
std::ostream& operator<<( std::ostream & out,const vector<T> & v )
{
    if( v.empty() ) return out << "[]";
    out << "[ " << *v.begin();
    std::for_each( v.begin()+1, v.end(), [&](T x){out<<", "<<x;} );
    return out << " ]";
}

int main()
{
    for( auto v : permutations_of_living_cells(3) )
        std::cout << v << "\n";
    std::cout << std::flush;
    return 0;
}