由火车进站引出的问题

1,2,3,4,5列火车进站出站,有哪些组合方式?对于进出站的方式与数据结构中的栈相同。如果 有n 列火车通过调度站,请设计一个算法,输出所有可能的调度结果。   

解题思路:栈具有先进后出、后进先出的特点,因此,任何一个调度结果应该是1 ,2 ,3 ,4全排列中的一个元素。由于进栈的顺序是由小到大的,所以出栈序列应该满足以下条件:对于序列中的任何一个数其后面所有比它小的数应该是倒序的。据此,本题可以通过算法产生n 个数的全排列,然后将满足出栈规则的序列输出。

那么第一个问题就是对火车出战可能顺序的全排列:

对于一个系列的全排列有一下几种方法:

number 1:

借助于STL库中的next_permutation函数。next_permutation的作用就是计算全排列。

next_permutation(str,str+strlen(str))是一个求str数组元素的下一个排列的函数。如果要走遍所有的排列数组元素必须已经有小到大有序!还有一个prev_permutation,要求由大到小有序。

  1. #include <iostream>  
  2. #include <algorithm>  
  3. using namespace std;  
  4. int array[] = {1, 2, 3, 4};  
  5. const int iArraySize = sizeof(array)/sizeof(int);  
  6. int main()
  7. {  
  8.     int iCnt = 0;  
  9.     cout << iArraySize << endl;  
  10.     sort(array, array + iArraySize);  //这里就是要求数组元素有小到大有序
  11.     do  
  12.     {  
  13.         for(int i = 0; i < iArraySize; i++)  
  14.         {  
  15.             cout << array[i];   
  16.         }  
  17.         cout << " ";  
  18.         iCnt++;  
  19.     } while (next_permutation(array, array + iArraySize));  
  20.       
  21.     cout << endl;  
  22.     cout << "Total number: " << iCnt << endl;  
  23.     return 0;  
  24. }  

number2:

不用STL函数,利用递归思想进行排列

  1. #include <iostream>  
  2. #include <vector>  
  3. #include <string>  
  4. using namespace std;  
  5. int array[] = {1, 2, 3, 4};  
  6. const int iArraySize = sizeof(array)/sizeof(int);  
  7. //删除str的第n个字符  
  8. void DeleteCharAt(string& str, int n)  
  9. {  
  10.     if (n < 0 || n >= str.length())  
  11.     {  
  12.         return;  
  13.     }  
  14.     string tmpStr(str.substr(n + 1));  
  15.     str = str.substr(0, n) + tmpStr;  
  16. }  
  17. //base 以该字符串作为基础字符串,进行选择性组合。   
  18. //buff 所求字符串的临时结果   
  19. //result 存放所求结果   
  20. void ListAll(string& strBase, string strBuff, vector<string>& result)  
  21. {  
  22.     if (strBase.length() <= 0)  
  23.     {  
  24.         result.push_back(strBuff);  
  25.     }  
  26.     for(int i = 0; i < strBase.length(); i++)  
  27.     {  
  28.         string tmp(strBase);  
  29.         DeleteCharAt(tmp, i);  
  30.         ListAll(tmp, strBuff + strBase[i], result);    
  31.     }  
  32. }  
  33. int main(){  
  34.     int iCnt = 0;  
  35.     string str = "1324";  
  36.     vector<string> vResult;  
  37.     ListAll(str, "", vResult);  
  38.     //Output the result  
  39.     for (int i = 0; i < vResult.size(); ++i)  
  40.     {  
  41.         cout << vResult[i] << " ";  
  42.     }  
  43.     cout << "/n";  
  44.     cout << "Total number: " << vResult.size() << endl;  
  45.     return 0;  
  46. }  
第二个问题就是判断排列组合能不能按栈的方式实现:


  1.     int i,j,k,l,m,flag=1,b[2];   
  2.     for(i=0;i<n;i++)    /* 对每个str[i] 判断其后比它小的数是否为降序序列*/   
  3.     {  
  4.         m=0;   
  5.         for(j=i+1;j<n&&flag;j++)
  6. {   
  7.             if (str[i]>str[j])  
  8.             {  
  9.                 if (m==0) b[m++]=str[j];//记录str[i]后比它小的数   
  10.                 else   
  11.                 {  
  12.                     //如果之后出现的数比记录的数还大,改变标记变量   
  13.                     if (str[j]>b[0]) flag=0;  
  14.                     //否则记录这个更小的数   
  15.                     else b[0]=str[j];   
  16.                 }   
  17.             }  
  18.         }   
  19.     }   

最后就可以输出满足条件的组合了。



非递归方法求全排列:

1、算法简述

要考虑全排列的非递归实现,先来考虑如何计算字符串的下一个排列。如"1234"的下一个排列就是"1243"。只要对字符串反复求出下一个排列,全排列的也就迎刃而解了。

如何计算字符串的下一个排列了?来考虑"926520"这个字符串,我们从后向前找第一双相邻的递增数字,"20"、"52"都是非递增的,"26 "即满足要求,称前一个数字2为替换数,替换数的下标称为替换点,再从后面找一个比替换数大的最小数(这个数必然存在),0、2都不行,5可以,将5和2交换得到"956220",然后再将替换点后的字符串"6220"颠倒即得到"950226"。

如果达到这个数的最大,比如1234-à4321,这个时候就结束整个循环。

如果输入是一个非最小数,如1324,则将它转换为最小数,如1234,再进行排序。排序算法用快排,可以自己写一个,如果快排不会的话,就先看会再来接着看,或者自己想一个靠谱的算法,也可以直接用VC库中的qsort(s , n , sizeof(s[0]) , cmp);各参数是什么意思就自己在下面多花点时间吧。

OK,下面看代码分析

2、代码分析

复制代码
 1 Prem( char *s )   //全排列函数
 2 {
 3     char *pEnd = s + strlen(s) - 1;
 4     char *p = pEnd;  //p代表替换点
 5     //q代表替换点的下一个数 ,pMax 代表替换点后比替换点大的最小数
 6     char *q = new char,*pMax = new char;  //注意初始化!!!
 7     while (p !=  s)          //p == s 就结束循环
 8     {
 9         q = p;
10         p--;
11         if (*p < *q)
12         {
13             pMax = FindMaxForOne(p,pEnd);  //找与替换点交换的点
14             Swap(p,pMax);         //交换
15             Reverse(q,pEnd);       //将替换点后所有数进行反转
16             Print(s);              //输出
17             p = pEnd;             //将替换点置最后一个点,开始下一轮循环
18         }
19         if (s == p) break;           //结束条件
20     }
21 }
复制代码

转载于:https://www.cnblogs.com/fangyan5218/p/10618265.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
货运车共有 n 节车厢,每节车厢将停放在不同的车站。假定 n 个车站的编号分别 为 1~n,车厢的编号与它们的目的地相同。货运车按照从第 n 站至第 1 站的次序经过这 些车站。为了便于从车上卸掉相应的车厢,必须重新排车厢,使各车厢从前至后按编号 1~n 的次序排。当所有的车厢按照这种次序排时,在每个车站只卸掉最后一节车厢 即可。可以在一个转轨站里完成车厢的重排工作,在转轨站中有一个入轨,一个出轨和k 个缓冲铁轨(位于入轨和出轨之间)。 图 3-1 给出了一个转轨站, 其中有 k=3 个缓冲铁轨 H1,H2 和 H3。开始时,n节车厢的货车从入轨处进入转轨站,车厢重排结束时各车厢按照编号1至编号n的次序从出轨处离开转轨站。在图 3-1(a)中,n=9,车厢从后至前的初始次序为 5,8,1,7,4,2,9,6,3。图 3-1(b)给出按所要求的次序重新排后的结果。 为了重排车厢,从前至后依次检查入轨上的所有车厢。如果正在检查的车厢就是下一个满足排的要求的车厢,可以直接把它放到出轨上。如果不是,则把它移动到缓冲铁轨上, 直到按输出次序要求轮到它时才将它放到出轨上。由于缓冲铁轨上车厢的进和出都是在其顶 部进行的,因此缓冲铁轨是按照 LIFO 的方式使用的。在重排车厢过程中,仅允许以下移动:  车厢可以从入轨移动到一个缓冲铁轨的顶部或者出轨上;  车厢可以从一个缓冲铁轨的顶部移动到的出轨上;

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值