算法课作业——归纳技术

返回主目录

2-1 输出全排列 (20分)

题目描述

请编写程序输出前n个正整数的全排列(n<10),并通过9个测试用例(即n从1到9)观察n逐步增大时程序的运行时间。

输入格式:
输入给出正整数n(<10)。

输出格式:
输出1到n的全排列。每种排列占一行,数字间无空格。排列的输出顺序为字典序,即序列a​1,a​2,⋯,a​n排在序列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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值