排列算法
输入样例:
3
3 1
2 3 1
3 1
3 2 1
10 2
1 2 3 4 5 6 7 8 9 10
输出样例:
3 1 2
1 2 3
1 2 3 4 5 6 7 9 8 10
解题思路:
该问题的关键在于确定一个排列生成下一个排列的算法。举例说明,以4721653为例,下一个排列需比4721653大,且为所有比4721653大的排列中最小的一个。找到一个包含若干个比4721653大的数字且包含最小数字的集合的最简单方法是:从低位到高位找一个降序的相邻数字,从该位置到最右侧位置挑一个恰好比当前位置数字大的数字,与其进行交换。例如,找到16,调换3和1的位置,得到下一个排列4723651.这样调换后,能得到一个比当前排列更大的排列,但未必是所有可能排列中最小的一个,但该数字给出了一个正确答案的上界。因此,还需要增加一个操作,使得到的排列是所有比当前排列大的排列中最小的一个。于是,对调换过的位置,从低的位置开始,对后续数字做升序排列,如651排列得到4723156,即可得到下一个排列。这是解这道题的核心!!!!!
c++代码实现:
include
using namespace std;
int main()
{
//1.创建一个数组用来存放这些数据
int m; //代表组数
int n; //代表数组中数据个数和循环操作数
int i = 0, j = 0, fi = 0, fj = 0;
int pl[1024] = { 0 };
cin >> m;
for (i = 0;i < m;i++) //共输入m组数据
{
cin >> n;
for (j = 0;j < n;j++) //将所给的排列初始化
{
cin >> pl[j];
}
int flag = 0;
//2.从后往前找到这个数组中第一组逆序排列的两个数,将其与之后刚好大于自己的数调换位置
for (fi = n - 1;fi > 0;fi--) //寻找逆序排列的循环
{
if (pl[fi] > pl[fi - 1]) //逆序排列出现,fi-1代表的数比fi代表的数小,在这之前我还要找到刚好大于这个数的数所在的位置
{
flag = 1;
int p, q; //用于调换后标记数之后的排序
int fj = fi - 1; //将这个数所在的位置记录下来
int temp = pl[fj]; //将这个数记录下来
int data = pl[fi]; //用于存放大于这个数的数
int k = fi; //记录逆序右侧数字所在位置
for (fi;fi < n - 1;fi++) //从逆序右侧数字位置开始找
{
if (pl[fi] < data && pl[fi]>pl[fj])
{
data = pl[fi]; //若一个数大于标记数且小于存入data的数,就把data的值换成这个数,这样找到的data就是刚好大于标记数的数
k = fi; //将这个数所在的位置标记一下
}
}
//进行到这里,已经找到了刚好比标记数大的数,接下来就是换位置,然后将后面的数字顺序排列,而这些全部建立在有逆序出现的情况下
pl[fj] = data; //标记数改成data
pl[k] = temp; //刚好大于标记数的数改成标记数大小
for (p = fj + 1;p <= n - 2;p++)
{
for (q = p + 1;q <= n - 1;q++)
{
if (pl[p] > pl[q])
{
int temp2 = pl[p];
pl[p] = pl[q];
pl[q] = temp2;
}
}
}
for (int l = 0;l < n;l++)
{
cout << pl[l] << " ";
}
break; //只要逆序出现直接跳出循环
}
}
if (flag == 0)
{
for (int l = 0;l < n;l++)
{
cout << pl[l] << " ";
}
}
}
system("pause");
return 0;
}
中间有些地方会有可以优化的点,就先不管了,搞定!
浙公网安备 33010602011771号