目录
2-1 输出全排列 (20分)
题目描述
请编写程序输出前n个正整数的全排列(n<10),并通过9个测试用例(即n从1到9)观察n逐步增大时程序的运行时间。
输入格式:
输入给出正整数n(<10)。
输出格式:
输出1到n的全排列。每种排列占一行,数字间无空格。排列的输出顺序为字典序,即序列a1,a2,⋯,an排在序列b1,b2,…,bn之前,如果存在k使得a1=b1,…ak=bk,并且ak+1<bk+1.
输入样例:
3
输出样例:
123
132
213
231
312
321
代码实现
#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 11;
int n;
int a[MAX_N] = { 0 }, visit[MAX_N] = { 0 };//a数组存放排列,从0开始;visit[i]标记数字i是否进入a数组,从1开始;
void output() {
for (int i = 0; i < n; i++) {
cout << a[i];
}
cout << endl;
}
void myPerm(int len) {
//len表示排列已确定位置的数字的个数
//本函数模拟了按字典序(通过for)轮流确定位置的过程
if (len == n)//说明a数组已经没有空位,可以输出
output();
else {
for (int i = 1; i <= n; i++) {//从小开始查询是否存在还没排进a的数字
if (visit[i] == 0) {//该数字还未排进a
a[len++] = i;//将该数字排进a,因此len++
visit[i] = 1;//标记该数字
myPerm(len);//递归查下一个排进a的数字
visit[i] = 0;//一次构造排列结束,将本数字的位置空出
len--;//同时长度减一
}
}
}
}
int main() {
cin >> n;
myPerm(0);
return 0;
}
2-2 前t个组合结果 (20分)
题目描述
组合结果
找出从自然数1、2、… 、n(0<n<=30)中任取r(0<r<=n)个数的组合,输出其中前t个组合结果。
输入格式:
在一行中输入n、r、t(1<=t<=C(n,r))。
输出格式:
按特定顺序输出前t个组合结果,每一个组合结果占一行,含第一个整数在内的每一个整数前面都用一个空格,最后一个整数后面没有空格。 特定顺序:每一个组合结果中的值从大到小排列,组合之间按逆字典序排列。
输入样例:
在这里给出一组输入。例如:
5 3 10
6 4 8
输出样例:
在这里给出相应的输出。例如:
5 4 3
5 4 2
5 4 1
5 3 2
5 3 1
5 2 1
4 3 2
4 3 1
4 2 1
3 2 1
6 5 4 3
6 5 4 2
6 5 4 1
6 5 3 2
6 5 3 1
6 5 2 1
6 4 3 2
6 4 3 1
代码实现
#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 30;
int n, r, t, counter = 0;
int a[MAX_N];
void output() {
for (int i = 0; i < r; i++) {
cout << ' ' << a[i];
}
cout << endl;
}
void tongbu(int m) {//使a[m-1]后的数递减
a[m] = a[m - 1] - 1;
if (m < r - 1)tongbu(m + 1);
}
void perm(int k) {
if (k == 1) {//最低位
while (a[r - k] != 0) {
output();
counter++;
if (counter == t)return;
a[r - k]--;
}
}
else {
while (a[r - k] != 0) {
perm(k - 1);
if (counter == t)return;
a[r - k]--;
tongbu(r - k + 1);
}
}
}
int main() {
cin >> n >> r >> t;
for (int i = 0; i < r; i++) {//初始化
a[i] = n - i;
}
perm(r);
return 0;
}
2-3 排列还原 (25分)
题目描述
牛牛的作业簿上有一个长度为n的排列A[1…n],这个排列包含了从1到n的n个数,但是因为某种原因,其中有一些位置(不超过10个)看不清了,但是牛牛记得这个排列的顺序对的数量是k,顺序对是指满足i<j且A[i]<A[j]的对数。请帮助牛牛计算出符合要求的排列数目。输入n,k与序列A,返回可能的存在排列数目。
输入格式:
输入的第一行包含两个整数n和k(1≤n≤100,1≤k≤n(n−1)/2),接下来的一行,包含n个数字表示排列A,其中等于0的项表示看不清的位置(不超过10个)。
输出格式:
输出一行表示合法排列的数目。
输入样例:
5 5
4 0 0 2 0
输出样例:
2
代码实现
#include<bits/stdc++.h>
using namespace std;
int n, k;
vector<int> canpo;
void pickUpPerm(vector<int> &perm) {
vector<int> tmp;
int exist=0;//exist是已存在的数的数量
for (int i = 1; i <= n; i++) {
tmp.push_back(i);
}
for (int i = 0; i < n; i++) {//
if (canpo[i]) {
remove(tmp.begin(), tmp.end(), canpo[i]);
exist++;
}
}
int num_perm=n-exist;//num_perm表示全排列的数的数量
for (int i = 0; i < num_perm; i++) {
perm.push_back(tmp[i]);
}
}
void createPerm(vector<vector<int> > &changshi, vector<int> &perm) {
do {
changshi.push_back(perm);
} while (next_permutation(perm.begin(), perm.end()));
}
void mergePerm(vector<vector<int> > &merge, vector<vector<int> > &changshi) { //
for (int i = 0; i < changshi.size(); i++) {
vector<int> insert;
int i_c = 0;
for (int j = 0; j < n; j++) {
if (canpo[j]) {
insert.push_back(canpo[j]);
}
else {
insert.push_back(changshi[i][i_c++]);
}
}
merge.push_back(insert);
}
}
int count(const vector<vector<int> > &merge)
{
int ans = 0;
for (int i = 0; i < merge.size(); i++){
int tmp = 0;
vector<int> one = merge[i];
for (int j = 0; j < one.size(); j++){
for (int jj = j + 1; jj < one.size(); jj++){
if (one[j] < one[jj])
tmp++;
}
}
if (tmp == k)
ans++;
}
return ans;
}
int main() {
cin >> n >> k;
for (int i = 0; i < n; i++) {
int num;
cin >> num;
canpo.push_back(num);
}
//得到需要全排列的数
vector<int> perm;
pickUpPerm(perm);
//得到尝试填入的数列
vector<vector<int> > changshi;
createPerm(changshi, perm);
//将两者合并
vector<vector<int> >merge;
mergePerm(merge, changshi);
//计算答案
cout << count(merge) << endl;
return 0;
}
2-4 行列式的计算 (20分)
题目描述
根据二维矩阵A[1…n][1…n]的行列式的定义计算行列式的值Det(A),其中涉及到1,2,…,n的全排列。输入n及二维矩阵A[1…n][1…n],返回A的行列式的值Det(A)。
输入格式:
输入的第一行包含一个整数n(1≤n≤10),接下来的n行对应矩阵A的n行, 每行包含n个数。
输出格式:
输出A的行列式的值Det(A)。
输入样例:
3
1 2 3
2 3 1
3 1 2
输出样例:
-18
代码实现
#include<bits/stdc++.h>
using namespace std;
int n;
//void perm1(int m, vector<vector<int> >& perm, vector<int>& tmp) {
// if (m == n-1) {
// perm.push_back(tmp);
// }
// else {
// for (int j = m; j < tmp.size(); j++) {
// swap(tmp[j], tmp[m]);
// perm1(m + 1, perm, tmp);
// swap(tmp[j], tmp[m]);
// }
// }
//}
void getPerm(vector<vector<int> > &perm) {
vector<int> tmp;
for (int i = 0; i < n; i++) {
tmp.push_back(i);
}
do {
perm.push_back(tmp);
} while (next_permutation(tmp.begin(), tmp.end()));
//perm1(0, perm, tmp);//也可以用书上的perm1
}
bool isRONeven(const vector<int> one) {
int counter = 0;
for (int i = 0; i < one.size(); i++) {
for (int j = i + 1; j < one.size(); j++) {
if (one[i] > one[j]) {
counter++;
}
}
}
if (counter % 2) {
return false;
}
else return true;
}
int productOfOnePerm(const vector<int> one,const vector<vector<int> >v ) {
int res=1;
for (int i = 0; i < n; i++) {
res *= v[i][one[i]];
}
return res;
}
int Det(const vector<vector<int> > v) {
//得到一个存放全排列的二维数组
vector<vector<int> > perm;
getPerm(perm);
//逐行计算逆序数,并根据逆序数确定正负加入结果
int ans = 0;//结果
for (int i = 0; i < perm.size(); i++) {
if (isRONeven(perm[i])) {//判断逆序数是不是偶数
ans += productOfOnePerm(perm[i], v);
}
else {
ans -= productOfOnePerm(perm[i], v);
}
}
return ans;
}
int main() {
cin >> n;
vector<vector<int> >v(n, vector<int>(n));
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> v[i][j];
}
}
cout << Det(v);
return 0;
}