邻位对换实现全排列

转自: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 <bits/stdc++.h>
using namespace std;

void Print(int A[], int n)
{
    int i;
    for(i=0;i<n-1;i++)
        printf("%d ",A[i]);
    printf("%d\n",A[i]);
}

bool Movable(int A[], bool direct[], int n) //direct参数用于接收每个元素移动方向的数组。
{
    int max = 1;//初始化最大可移动数为1,因为规定1是最小的数,可以自己设定。
    int pos = -1;//初始化最大可移动数的位置为-1.
    /*下面先找到最大可移动数位置*/
    for (int i = 0; i<n; i++)
    {
        if (A[i] < max)
            continue;
        if ((i < n - 1 && A[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<n; i++)
    {
        if (A[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; i<n; i++)
        direct[i] = false;//初始化移动方向为false,表示从右向左。
    do
    {
        Print(A, n);
        if (A[n - 1] == n)
        for (int i = n - 1; i>0; 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<n;i++)
        arr[i]=i+1;
    Full_Array(arr,n);
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值