蛮力置换交换

Brute Force Permutation Swapping

本文关键字:交换      更新时间:2023-10-16

我一直在研究一种暴力算法来生成给定集合的所有排列。最后,我想把这些排列中的每一个都输入到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。我的算法哪里出了问题?

关于排列的wiki文章包括一个常用算法,用于按字典顺序生成所有排列,从一个按顺序递增的整数数组开始,到该数组反转结束。wiki下一个排列。

如果处理对象数组,可以生成索引0到n-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);
}

这假定原始数组中没有重复的元素。让它考虑重复的元素并不难。