邻位对换实现全排列

转自:https://blog.csdn.net/sm9sun/article/details/77373258

是由Johnson-Trotter首先提出。如果已知n-1个元素的排列,将n插入到排列的不同位置,就得到了n个元素的排列。用这种方法可以产生出任意n个元素的排列。但是,为了产生n个元素的排列,我们必须知道并存储所有n-1个元素的排列,然后才能产生出所有n阶排列,这是一个很大的缺点。

该算法的实质是交换排列中某两个相邻的元素来产生一个新的排列。按照下面所说的算法就可以从原始排列开始,生成全体排列。具体算法可以描述如下:

规定排列中每一个元素都有一个(可移动的)方向,可以设想在每个元素上有一个箭头,箭头的指向就是元素的(可移动的)方向。如果一个元素的箭头所指的相邻的元素比该元素小时,称该元素处于活动状态。当一个元素在排列的左端,其方向向左,或一个元素在排列的右端,其方向向右,该元素就不处在活动状态,1总是处在不活动的状态。

第一步:初始化n个元素的排列为123……n,并规定其元素的方向都是向左的,元素的方向用一个数组b来表示,当b[i]=0,表示第i个元素的方向向左,当b[i]=1时表示地i个元素的方向向右。

第二步:在排列中找出排列中所有处于活动状态的元素中最大的一个,

第三步:将它与它所指向相邻元素交换。

把排列中大于上面找出的处在活动状态的最大元素大的其他元素的方向倒转。

要得到n个元素的全部排列,可以从原始排列开始,通过上述算法产生新的排列,一直到排列的全体元素都成为不活动的,全部排列就都已生成。

B - Bell Ringing Gym - 100781B 裸题

#include 
using namespace std;

void Print(int A[], int n)
{
    int i;
    for(i=0;i A[i + 1] && direct[i]) || (i > 0 && A[i] >A[i - 1] && !direct[i]))
        {
            max = A[i];
            pos = i;
        }
    }
    /*下面对它进行移动*/
    if (pos == -1)
        return false;
    if (direct[pos])
    {
        swap(A[pos], A[pos + 1]);
        swap(direct[pos], direct[pos + 1]);
    }
    else
    {
        swap(A[pos], A[pos - 1]);
        swap(direct[pos], direct[pos - 1]);
    }
    /*最后调整所有比最大可移动数大的数的方向*/
    for (int i = 0; i max)
        direct[i] = !direct[i];
    }
    return true;
}

void Full_Array(int A[], int n)
{
    bool* direct = new bool[n]; //产生一个记录每个元素移动方向的数组
    sort(A, A + n); //将原序列变成一个升序
    for (int i = 0; i0; i--)
        {
            swap(A[i], A[i - 1]);
            swap(direct[i], direct[i - 1]);
            Print(A, n);
        }
        else
        for (int i = 0; i < n-1; i++)
        {
            swap(A[i], A[i + 1]);
            swap(direct[i], direct[i + 1]);
            Print(A, n);
        }
    } while (Movable(A, direct, n));

    delete[]direct;
}

int main()
{
    int arr[8]={0};
    int n;
    scanf("%d",&n);
    int i;
    for(i=0;i

 

你可能感兴趣的:(ACM知识点)