生成所有错位排列的算法

所谓N元错位排列,就是指对应于1,2,--,N的N元排列Im(m=1,2,---,N),满足Im!=m,算法的目的是构造出所有这样的错位排列,依据的基本思想是回溯法,在沿栈向下试探的过程中逐步扩大部分错位排列的规模,当发现无法找到下一个部分错位排列的元素时就向上回溯,继续试探,当栈空间首元素stack[0]==N+1时,表明首元素为2,--,N的所有错位排列已全部试探得到,错位排列生成完毕,退出循环。这里给出算法,该算法生成对应于1,2,---,N的所有N元错位排列

代码(C++)

  1 #include "stdafx.h"
  2 #include <vector>
  3 #include <iostream>
  4 using namespace std;
  5
  6 #define N 5   //问题规模,生成对应于1,2,---,N的所有N元错位排列
  7
  8 int Search(const vector<bool> &occupy, int i ,int j)
  9 {
 10     for (; i < occupy.size(); ++i)
 11     {
 12         if (i + 1 != j && occupy[i] == false)
 13         {
 14             return i + 1;
 15         }
 16     }
 17     return 0;
 18 }
 19
 20 int main()
 21 {
 22     vector<int> a(N, 0);
 23     vector<bool> occupy(N, false);  //对于栈中已生成的错位排列中的任意值i,occupy[i-1]==true,对于1,2---,N中不在错位排列栈中的任意元素i,occupy[i-1]=false
 24     bool TF = true;  //循环过程中回溯至本层为false,前进至本层为true
 25     int i = 0;  //存放错位排列的栈的栈顶指针
 26     int count = 0;  //统计错位排列数
 27     while (true)
 28     {
 29         if (i == 0)
 30         {
 31             if (TF == true)
 32             {
 33                 a[i] = 2;
 34                 occupy[a[i] - 1] = true;
 35                 ++i;
 36             }
 37             else
 38             {
 39                 occupy[a[i] - 1] = false;
 40                 ++a[i];
 41                 if (a[i] > N)
 42                     break;
 43                 occupy[a[i] - 1] = true;
 44                 ++i;
 45                 TF = true;
 46             }
 47         }
 48         else
 49         {
 50             int temp;
 51             if (TF == true)
 52             {
 53                 if ((temp = Search(occupy, 0, i + 1)) == 0)
 54                 {
 55                     --i;
 56                     TF = false;
 57                     continue;
 58                 }
 59                 else
 60                 {
 61                     a[i] = temp;
 62                     occupy[temp-1] = true;
 63                 }
 64             }
 65             else
 66             {
 67                 if ((temp = Search(occupy, a[i], i + 1)) == 0)
 68                 {
 69                     occupy[a[i] - 1] = false;
 70                     --i;
 71                     continue;
 72                 }
 73                 else
 74                 {
 75                     occupy[a[i] - 1] = false;
 76                     a[i] = temp;
 77                     occupy[temp - 1] = true;
 78                 }
 79             }
 80
 81             if (i != a.size() - 1)
 82             {
 83                 ++i;
 84                 TF = true;
 85             }
 86             else
 87             {
 88                 ++count;
 89                 cout << "第"<<count<<"个错位排列:" << endl;
 90                 for (const int &m : a)
 91                 {
 92                     cout << m << " ";
 93                 }
 94                 cout << endl;
 95                 for (int j = 1; j <= N; ++j)
 96                 {
 97                     cout << j << " ";
 98                 }
 99                 cout << endl;
100                 cout << endl;
101                 TF = false;
102             }
103
104         }
105     }
106     return 0;
107 }

运行结果(N=5时)

原文地址:https://www.cnblogs.com/WSKIT/p/9189279.html

时间: 2024-07-30 11:51:32

生成所有错位排列的算法的相关文章

《程序设计中的组合数学》——全错位排列

承接上文,这次以递推的思维,介绍组合学当中一个很经典的问题. 这个问题最开始由瑞士数学家欧拉提出,原始的问题被叫做“装信封问题”,问题的大意就是:有n封信和n封它们各自对应的信封,如果邮递员想要把每封信都放在不属于这封信的信封,那么请问有多少种排法.(这邮递员真无聊)  想必这个问题在中学阶段数学的[排列组合]都有过接触,但是我记忆非常深刻的是,老师讲到这个模型,自己找了一下n = 5的情况就停止了,然后让大家把前面的数字序列背下来.今日故地重游不禁觉得老师教的好坑爹,搞学习还是要亲历亲为自主探

全错位排列

全错位排列是由著名数学家欧拉提出的. 最典型的问题是装错信封问题 一个人写了n封不同的信及相应的n个不同的信封,他把这n封信都装错了信封,问都装错信封的装法有多少种? 用a.b.c,d--表示n份相应的写好的信纸,A.B.C,D--表示写着n位友人名字的信封,错装的总数为记作f(n). 假设把a错装进B中,然后接下来我们可以分为两种情况, 第一种是b错装进了A中,那么问题就变为c,d,e-..n-2个信纸放入C,D,E--n-2个信封时完全放错时完全装错有多少种,有f(n-2)种 第二种是b错装

hdoj 2049 不容易系列之(4)——考新郎 【全错位排列】【组合数】

方法如题. 全错位排列 不容易系列之(4)--考新郎 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 21347    Accepted Submission(s): 7857 Problem Description 国庆期间,省城HZ刚刚举行了一场盛大的集体婚礼,为了使婚礼进行的丰富一些,司仪临时想出了有一个有意思的节目,叫做"考新郎

关于错位排列

今天弄了一下错位排列,似乎挺简单的... 错位排列问题的描述大致如下:给定n个信封以及n个信,每个信只能容纳在,第i号信需要放在第i号信封里,现在所有信封的位置都是错误的,求不同的错误方案数. 因为第i号信是不在第i号信封里面的,这样的话我们可以模拟出以下n*n的矩阵(其中1表示信封错误的位置不能是此处): 1,0,0,0 不难看出来,对于第一行来说我们有3种不同的方案,在某个点被占据时,其所在的排,列,都没有意义了,这样的话我们可以得到3个新的矩阵: 0,1,0,0 1: 0,0,0 2:0,

PHP树生成迷宫及A*自动寻路算法

PHP树生成迷宫及A*自动寻路算法 迷宫算法是采用树的深度遍历原理,这样生成的迷宫相当的细,而且死胡同数量相对较少! 任意两点之间都存在唯一的一条通路. 至于A*寻路算法是最大众化的一全自动寻路算法 完整代码已上传,http://download.csdn.net/detail/hello_katty/8885779 ,此处做些简单解释,还需要大家自己思考动手.废话不多说,贴上带代码 迷宫生成类: /** 生成迷宫类 * @date 2015-07-10 * @edit http://www.l

java排列组合算法代码实现

原文:java排列组合算法代码实现 源代码下载地址:http://www.zuidaima.com/share/1550463479024640.htm java排列组合算法,有需要研究的童鞋可以下载,运行结果如下: package com.zuidaima.test; /** *@author www.zuidaima.com **/ public class Pailie { public static void main(String[] args) { int[] ia = {1, 2,

c# 排列组合算法

//排列组合 public class FullArrange { /// <summary> /// 排列组合 /// </summary> /// <param name="str">字符串</param> /// <param name="splitStr">分割的符号,比如";"</param> /// <returns></returns>

错位排列及有关例题

求n个数(不相同)错位排列的个数. 何为错位排列?定义如下:对于n的一个排列a1,a2,a3...an. 如何求解错位排列? 考虑动态规划的解法. 前i个元素时如何进行状态转移? (一)首先由于要求错位排列,第i个元素肯定不会放在自己的位置上,故第i个元素的位置有i-1种选择. (二)对于剩下的i-1个元素,选择其中的一个元素k.这时候k有两种选择: 1. 放在第i个元素的位置上,宏观上相当于i与k的位置互换了.而剩下的i-2个元素依然要求错位排列. 2. 不放在第i个元素的位置上,则相当于剩下

[Luogu4921]情侣?给我烧了![错位排列]

题意 题意很清楚 \滑稽 分析 对于每一个询问 \(k\) ,记 \(g(x)\) 表示 \(x\) 对情侣都错开的方案总数,那么答案可以写成如下形式: \[ {ans}_k= \binom{n}{k}\times A_n^k\times 2^k\times g(n-k) \] 考虑如何求 \(g(x)\) (一个错位排列). 考虑第一排,一共有三种情况:两男两女或者一男一女(不配对). 两男:顺次选出两男的方案数为 \(x(x-1)\) ,然后考虑他们的配偶在之后的配对情况: 如果强制不配对,