共42道题,当前是第14

初赛真题

(排列数)输人两个正整数 $n,m(1 < n < 20. 1 < m < n)$ , 在 $1 \sim n$ 中任取 $m$ 个数,按字典序从小到大输出所有这样的排列。

例如: 输入: 3 2 输出:

1 2
1 3
2 1
2 3
3 1
3 2
#include <iostream>
#include <cstring>
using namespace std;

const int SIZE = 25;
bool used[SIZE];
int data[SIZE];
int n, m, i, j, k;
bool flag;

int main() {
	cin >> n >> m;
	memset(used, false, sizeof(used));
	for (i = 1; i <= m; i++) {
		data[i] = i;
		used[i] = true;
	}
	flag = true;
	while (flag) {
		for (i = 1; i <= m - 1; i++) cout << data[i] << " ";
		cout << data[m] << endl;
		flag = ___(1)___;
		for (i = m; i >= 1; i--) {
			___(2)___;
			for (j = data[i] + 1; j <= n; j++)
				if (!used[j]) {
					used[j] = true;
					data[i] = ___(3)___;
					flag = true;
					break;
				}
		if (flag) {
			for (k = i + 1; k <= m; k++)
				for (j = 1; j <= ___(4)___; j++)
					if (!used[i]) {
						data[k] = j;
						used[j] = true;
						break;
					}
				___(5)___;
			}
		}
	}
	return 0;
}


1. A。
2. D。
3. A。
4. A。
5. D。

这段代码的主要原理是通过一个已经有的排列,推断出该排列在字典序中的下一个排列。操作方法很简单:假设当前排列中的第 $i$ 个的值为 `data[i]` ,那么就倒着寻找第一个可以使 `data[i]` 变大的下标,设为 $k$ ,令 `data[k]` 变成一个更大的数字,这样就可以使得字典序增大。同时为了保证这是在字典序上直接与当前排列相邻的排列,我们需要让 `data[k+1...m]` 这部分构成的序列字典序最小(在不修改 `data[1...k-1]` 的情况下)。所以我们需要重新对其值进行分配,也就是代码中 `if(flag)` 分支的部分。

Question

1. (1) 处应填( )

2. (2) 处应填( )

3. (3) 处应填( )

4. (4) 处应填( )

5. (5) 处应填( )

陈伦制作 版权所无 粤ICP备16127491号-1