0
点赞
收藏
分享

微信扫一扫

2-3 排列还原 (25 分)(排列问题实例)

一点读书 2022-03-24 阅读 97

牛牛的作业簿上有一个长度为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

 这里还是用了模板,注释已经写很清楚了,看不懂的可以dd我。

#include<iostream>
#include<vector>
#include<cstring>
#include<string.h>
using namespace std;
vector<vector<int> > bt(10000, vector<int>(0));//用于记录每种排列的结果
int n, k;
int cnt = 0;
int order[1003] = { 0 };
int chosen[1003] = { 0 };
void cal(int x, int k, vector<int>& v)//这里是排列的模板
{
	if (x == k + 1)
	{
		for (int i = 1; i <= k; i++)
		{
			bt[cnt].push_back(v[order[i] - 1]);//关键是要每次将order里的值都存进向量bt
		}
		cnt++;//记录操作次数
		return;
	}
	for (int i = 1; i <= k; i++)
	{
		if (chosen[i]) continue;
		order[x] = i;
		chosen[i] = 1;
		cal(x + 1, k, v);
		order[x] = 0;
		chosen[i] = 0;
	}
}
int main()
{
	//count记录每种结果中顺序对的个数,ct记录满足count=k的数量
	int count = 0, ct = 0;
	cin >> n >> k;
	int* a = new int[n + 2];
	int b[103] = { 0 };
	memset(b, 0, (103) * sizeof(int));
	vector<int> v, vp;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		if (a[i] != 0) b[a[i]] = 1;
		if (a[i] == 0) v.push_back(i);//记录为0的位置
	}

	
	int cntz = 0;//记录需要排列数字的个数
	for (int i = 1; i <= n; i++)
	{
		if (b[i] == 0)
		{
			vp.push_back(i);//记录为缺少的数字
			cntz++;
		}
	}

	cal(1, cntz, vp);//调用函数计算各种排列的结果
	for (int i = 1; i <= cnt; i++)
	{
		for (int j = 0; j < bt[i - 1].size(); j++)//填充cnt种排序结果至数组a
		{
			a[v[j]] = bt[i - 1][j];
		}
		for (int i = 1; i < n; i++)
		{
			for (int j = i + 1; j <= n; j++)
			{
				if (a[i] < a[j]) count++;//计算顺序对的个数
			}
		}
		if (count == k) ct++;//当顺序对为k时,ct++
		count = 0;
	}
	cout << ct;


}
举报

相关推荐

0 条评论