蛮力排列交换

时间:2014-10-16 00:13:29

标签: c++ algorithm brute-force

我一直致力于使用强力算法来生成给定集合的所有排列。最后,我想将这些排列中的每一个都输入到nxn矩阵中,以测试它是否是一个有效的魔方。 - 我知道有办法轻松生成魔法广场 - 但这不是我想做的。我专注于它的蛮力方面。

对于一组3个元素,它的工作非常精彩。但是,一旦我使用4个或更多元素,我就会失去一些排列。仅从查看4的输出,我就缺少7种排列。

#include <stdio.h>
#include <iostream>

using namespace std;


//ms = magic square
//n = size
void perm(int ms[], int n) {
    int pivot = 0;
    int index = 0;
    int pivBit = 1;
    int fin = 0;
    int hold = 0;

    //While we are not finished
    while (fin == 0)  {
        //Incriment the index
        ++index;
        if (index >= n) {
            index = 0;
        }
        //if index is equal to the pivot
        if (index == pivot) {
            //Is this the first time visiting the pivot?
            if (pivBit == 0) {
                //Are we at the beginning again?
                if (index == 0 && pivot == 0)
                {
                    fin = 1;
                }
                pivBit = 1;
                ++index;
            }
            //Second time visiting? 
            else {
                pivBit = 0;
                ++pivot;
                if (pivot >= n) {
                    pivot = 0;
                }
            }
        }

        //If we are out of bounds
        if (index >= n) {
            index = 0;
        }

        //swap
        hold = ms[index];
        ms[index] = ms[pivot];
        ms[pivot] = hold;

        for (int i = 0; i < n; ++i) {
            cout << ms[i];
            if (i < n - 1) {
                cout << ", ";
            }
            else {
                cout << endl;
            }


        }

    }

}



int main() {

    cout << "Are you ready to brute force, my brother?" << endl;

    //Set
    int magicsquare[] = { 1, 2, 3, 4};
    int size = 4;

    perm(magicsquare, size);

    getchar();
    return 0;
}

我的输出是:

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

看着它,我已经可以看到我错过了1 4 3 2和1 3 2 4。 我的算法在哪里出错?

2 个答案:

答案 0 :(得分:1)

生成所有排列的最简单方法是递归。对于每个i,将第i个元素交换到0位置。然后递归地找到剩余数组的所有排列。

int buf[1000], n;  // better to wrap these in a class...

void permute(int *a, int a_len) {
  if (a_len == 1) {
    for (int i = 0; i < n; i++) printf("%d ", buf[i]);
    printf("\n");
  } else { 
    for (int i = 0; i < a_len; i++) { 
      swap(a, 0, i);
      permute(a + 1, a_len - 1);
      swap(a, 0, i);
    }
  }
}

void run(int buf_len) {
  for (int i = 0; i < buf_len; i++) buf[i] = i + 1;
  n = buf_len;
  permute(buf, buf_len);
}

这假设原始数组中没有重复的元素。考虑到重复的因素并不难。

答案 1 :(得分:1)

关于置换的维基文章包括一个常用的算法,用于按字典顺序产生所有排列,从一个顺序递增的整数数组开始,以反转的数组结束。 wiki next permutation

如果处理一个对象数组,你可以生成一个索引0到n-1的数组,并在索引上使用下一个排列来产生对象数组的所有排列。

您还可以对下一个排列进行网络搜索,以查找类似的算法。递归的产生所有排列,但不是按字典顺序排列。