枚举原先相邻的数不相邻的排列的算法

考虑如下问题,编号依次为1,2,—n的n个人依照编号次序排成环形,现要将这n个人重新排列成环形,使得在原先的环形排列中彼此相邻的两个人在新的环形排列中不相邻,试设计算法枚举满足要求的所有新的环形排列。
注意在满足要求的任意一个环形排列中以排列中n个人的每一个人作为起点顺时针或逆时针绕排列一圈 回到作为起点的人所形成的序列对应的都是同一种合法的环形排列,因此在枚举过程要求仅保留从n个人中仅一个人出发形成的顺时针(或逆时针)排列,注意是在算法运行过程中剔除多余环形排列,而不是从生成的含有重复结果的排列集合中剔除重复环形排列
C++代码如下:

#include <iostream>
#include <vector>

using namespace std;

size_t N = 9;
size_t pre_pos(size_t pos)
{
    if (pos == 0)
        return N - 1;
    return pos - 1;
}

size_t next_pos(size_t pos)
{
    if (pos == N - 1)
        return 0;
    return pos + 1;
}

size_t find_next_pos(size_t num, vector<size_t> &pos_of_Num, vector<size_t> &Num_in_pos, size_t cur_pos, size_t count)
{
    size_t pre = pre_pos(cur_pos);
    size_t next = next_pos(cur_pos);
    for (; num < N; ++num)
    {
        if (pos_of_Num[num] == N)
        {
            size_t adj_num_1 = pre_pos(num);
            size_t adj_num_2 = next_pos(num);
            if ((pos_of_Num[adj_num_1] == N || pos_of_Num[adj_num_1] != pre && pos_of_Num[adj_num_1] != next) &&
                (pos_of_Num[adj_num_2] == N || pos_of_Num[adj_num_2] != pre && pos_of_Num[adj_num_2] != next))
            {
                if (count != 0 && cur_pos == N - 1 && Num_in_pos[1] > num)
                    return N;
                return num;
            }
        }
    }
    return N;
}

int main()
{
    vector<size_t> pos_of_Num(N, N);   //各数的位置
    vector<size_t> Num_in_pos(N, N);  //各位置上的数
    size_t i = 1;
    size_t count = 0;
    pos_of_Num[0] = 0;
    Num_in_pos[0] = 0;
    while (true)
    {
        bool end = Num_in_pos[i] == N;
        size_t r;
        if ((r = find_next_pos(end ? 1 : Num_in_pos[i] + 1, pos_of_Num, Num_in_pos, i, count)) == N)
        {
            if (i == 1)
                break;
            if (Num_in_pos[i] != N)
            {
                pos_of_Num[Num_in_pos[i]] = N;
                Num_in_pos[i] = N;
            }
            --i;
            continue;
        }

        if (!end)
            pos_of_Num[Num_in_pos[i]] = N;
        Num_in_pos[i] = r;
        pos_of_Num[r] = i;

        if (i != N - 1)
        {
            ++i;
        }
        else
        {
            ++count;
            cout << "第" << count << "个解:" << endl;
            cout << "pos:";
            for (size_t i = 1; i <= N; ++i)
            {
                cout << i << " ";
            }
            cout << endl;

            cout << "num:";
            for (size_t i = 0; i < N; ++i)
            {
                cout << Num_in_pos[i] + 1 << " ";
            }
            cout << endl;
            cout << endl;
        }
    }
    cout << "共有" << count << "个解" << endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值