身高排队算法-(较优解):12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?
来源:互联网 发布:用户画像数据建模方法 编辑:程序博客网 时间:2024/04/30 02:07
本人对解决算法有兴趣,曾在网上看到过一道阿里巴巴的面试题.
题目是这样的:12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?
所以自己也考虑了一个算法,也在网上看到别人的不同的算法。感觉我这个算法遍历效率很高,而且也很简洁(不敢用最来形容,怕强中更有强中手,当然如果能推导出公式来求解的话肯定会比我这个算法快,这个公式是F(n) = (n! / ((n/2)! * (n/2)!))/ (n/2 +1)).
我的算法思想是这样的:
(1)把排队的问题转换成数字排列问题,类似于0- 11这12个数排成2行。
(2)可以只考虑前一排的情况,因为只要前一排是符合某些条件,剩余的数按顺序放后排自然能满足条件。
(3)第一排数要符合的条件是:
下面数值表示的是位置,
0 1 2 3 4 5
6 7 8 9 10 11
对于位置0,可能的数的范围是0
对于位置1,可能的数的范围是1,2
对于位置2,可能的数的范围是2,3,4
对于位置3,可能的数的范围是3,4,5,6
对于位置4,可能的数的范围是4,5,6,7,8
对于位置5,可能的数的范围是5,6,7,8,9,10
这样可以推导出:
对于位置为n的数,其数的范围是[n, 2n].
这样对于0-5的位置的数的范围就是[{0,1,2,3,4,5}, {0,2,4,6,8,10}],
我们把这个0-5的位置的数当成一个大的数来看待,对其进行++操作,只不过进位的时候是按每个位置的数的范围来进行进位。
比如:
1.目前数是{0,1,2,3,4,5}, ++操作后,数变为{0,1,2,3,4,6},因为6小于且等于位置5的最大值2n = 10,所以此组合是个符合要求的组合。
2.又如目前数是{0,1,2,3,4,10}, ++操作后,数变为{0,1,2,3,4,11},因为11大于位置5的最大值2n = 10, 因此要进位,这样位置4的数++,再检查位置4的数++后是5,小于且等于位置4的最大值2n = 8,这个位置符合条件,而位置5的数要置"0",这个0不能是再从范围的起始值开始,而是要等于位置4的数+1.因为从起始值开始的数肯定是小于位置4的值的。
3.以此类推,如果目前数是{0,1,4,6,8,10},++操作后,需要进位,一步一步往前进位,最终进位位置1的数,数就变成了{0,2,5,7,9,11},然后要把位置1之后位置的每个位置的数置"0", 等于前一个位置的数+1,这样最后数就是{0,2,3,4,5,6}.
4.检查此数组合是否符合条件是,检查最后一个数是否小于且等于其位置的最大值。
附算法如下:
#include <iostream>
#include <vector>
using namespace std;
class pai2dui
{
public:
pai2dui(int n)
:mMaxNum(n / 2)
,mCount(0)
,mAllCount(0)
{
if (n > 1)
{
mCount = 1;
for(int i = 0; i < n / 2; i++)
{
mData.push_back(i);
}
}
}
void run()
{
if(mMaxNum <= 0)
{
return;
}
int i = mMaxNum - 1;//从最后一个数开始++操作
while (i)
{
++mData[i]; //对位置为i的数进行++操作
mAllCount++; // 总循环的此数计数.
if (mData[i] <= 2 * i)
{// 如果该位置的数不超过对应位置的最大值,那么对其后面的位置的数置”0”.
for (int j = i + 1; j < mMaxNum; j++)
{//其后面位置的数等前面位置的数+1,能确保这个数是进位后”最小”符合的数的组合
mData[j] = mData[j - 1] + 1;
}
}
else
{// 如果该位置的数超过了对应位置的数的最大值,将数的位置往前移动一位,然后使用
// continue重新++操作。
i--;
continue;
}
if (mData[mMaxNum - 1] <= 2 * (mMaxNum - 1))
{//检查最后一位的数是否小于且等于其位置的最大值,如果是的话,此数组合符合要求
// 计数并打印
++mCount;
for(int k = 0; k < mMaxNum; k++)
{
cout<< mData[k] << " ";
}
cout << endl;
// 把++操作的数的位置置回最后一个位置。
i = mMaxNum - 1;
}
else
{ // 如果大于其位置的最大值,说明已遍历完毕,超过了此数组合的最大值。
return;
}
}
}
void print()
{
cout<<mCount<<endl;
cout<<mAllCount<<endl;
}
private:
int mMaxNum;
vector <int> mData;
int mCount;
int mAllCount;
};
int main(int argc, char* argv[])
{
int n;
while(cin>>n)
{
pai2dui p(n);
p.run();
p.print();
}
return 0;
}
谢谢指教。
- 身高排队算法-(较优解):12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?
- 12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?
- 12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人 高,问排列方式有多少种?
- 12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?
- C++12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?
- 12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少
- 12个高矮不同的人,排成两排,
- 12个高矮不同的人,排成两排
- 12个高矮不同的人,排成两排
- 12个高矮不同的人,排成两排
- 12个高矮不同的人排成两排
- 12个高矮不同的人排成两排
- 12个高矮不同的人,排成两排
- 12个高矮不同的人,排成两排/Catalan数
- 12个高矮不同的人,排成两排/Catalan数
- 12个高矮不同的人,排成两排——Catalan数
- 12个高矮不同的人,排成两排/Catalan数
- catalan数,两排,分别从低到高排序,第二排相应的比第一排高
- out与ref的区别
- [转]_stdcall 与 _cdecl 的区别
- C#读取dbf文件
- SQL Server孤立用户解决步骤
- Go环境搭建
- 身高排队算法-(较优解):12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?
- ExtJS中Ext.Ajax.request与form1.getForm().submit的基本区别
- PHP中调用系统命令的system(),exec(),passthru()
- Android检测手机或PAD是否连网
- 设置DIV自动撑高,并设置最低高度
- windows下ftp带时间参数
- .NET中break、return、continue三者的区别
- 解决点击一个按钮如何打开一个已安装好的应用程序
- 命令格式