有一个长度为n的排列A,这个排列包含了从1到n的n个数,但有一些数字先用0代替

在这个数列中顺序对的数量是K个,顺序对的是指当i<j时,A[i]<A[j],求符合这个要求的序列的个数



#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

vector<int> v;
vector<int> vv;
vector<vector<int>> ret;
int sumunknow(int n)
{
	//n!
	int count = 1;
	for (int i = 1; i <= n; ++i){
		count *= i;
	}
	return count;
}

int main()
{
	int n, k;
	int x;
	int unknow = 0;
	int count;
	while (cin >> n >> k){
		//找出所有看不清的数字放到v中
		for (int i = 0; i < n; ++i){
			cin >>x;
			v.push_back(x);
			if (x == 0)
				++unknow;
		}
		count = sumunknow(unknow);//有count种可能的排列(unknow的阶层)
	
		for (int i = 1; i <= n; ++i){//i为从1~n的数
			int j = 0;
			for (; j < v.size(); ++j){
				if (v[j] == i)//i这个数已经存在,即能看清的数,跳出执行下一次循环
					break;
			}
			if (j == v.size())
				vv.push_back(i);//存放的是看不清的那几个数,且这些数是升序存放的
		}

		int needpushcount=0;
		while (needpushcount<count){
			next_permutation(vv.begin(), vv.end());
			int k = 0;
			vector<int> subret;
			for (int i = 0; i < v.size(); ++i){
				if (v[i] != 0){
					subret.push_back(v[i]);
				}
				else{
					subret.push_back(vv[k++]);
				}
			}
			ret.push_back(subret);
			++needpushcount;
			//NextPermutation(vv.begin(),vv.end());//自己模拟的库函数,必须放在此处,不能放在前面,因为实现的功能暂不支持
		}

		int result = 0;
		int sum = 0;
		for (int i = 0; i < count; ++i){
			for (int j = 0; j < v.size(); ++j){
				for (int k = 1; k < v.size()-j; ++k){
					if (ret[i][j] < ret[i][j + k])
						++sum;
				}
			}
			if (sum == k)//***
				++result;
			sum = 0;
		}
		cout << result<<endl;
	}

	return 0;
}


next_permutation()这个函数是C++的一个函数

内部实现原理:

如果要比较的数列中只有一个元素的话返回直接false;否则使变量__i指数列的最后一个元素,进入循环 ;

从最右边边开始比较俩个相邻的元素,直到找到左边比右边小的那两个数,左边那个就是待交换的数

再从最右边开始,找比代替换的那个数大的第一个元素,然后交换这两个数,交换之后反转被替换元素之后的所有元素


自己实现了一个NextPermutation(),只针对数据是int类型的操作

#include <iostream>
using namespace std;

void Reverse(int* start, int* end)
{
	--end;
	while (start < end){
		swap(*start, *end);
		++start;
		--end;
	}
}

//[)前闭后开    且此函数只处理int类型的数据
bool MyNextPermutation(int first,int last,int* arr)
{
	if (first >= last || first + 1 == last)
		return false;
	int i = last - 1;
	int ii = i;
	--i;
	while (i >= 0 && arr[i] >= arr[ii]){
		--i;
		--ii;
	}
	if (i < 0)
		return false;
	int j = last - 1;
	while (arr[j] <= arr[i])
		--j;
	swap(arr[i],arr[j]);
	Reverse(&arr[ii],&arr[last-1]+1);
	return true;
}
int main()
{
	int arr[] = { 1, 2, 3, 4 };
	//int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
	bool ret = true;
	while (ret){
		cout << arr[0] << arr[1] << arr[2] << arr[3] << endl;
		/*cout << arr[0] << arr[1] << arr[2] << arr[3] <<\
			arr[4] << arr[5] << arr[6] << arr[7] << endl;*/
		ret=MyNextPermutation(0,sizeof(arr)/sizeof(arr[0]),arr);
	}
	system("pause");
	return 0;
}


使用这个函数的时候一定要先升序排列,我的这篇博客有详解:

http://lingdandan.blog.51cto.com/10697032/1773352


《完》