0
点赞
收藏
分享

微信扫一扫

【排列枚举】next_permutation的应用

next_permutation


排列枚举就是枚举所有元素的排列情况,而对于此类题目大多数都可以用 next_permutation函数生成各个元素的不同排列解决,因此本文重在学习使用这个函数解决问题。

用法剖析

next_permutation(start,end)algorithm标准库函数,它可以重新排列[start,end)范围内的数组并产生严格的下一个字典序排列。如果有字典序更高的排列方式,就按这种方式排列并返回为true,否则就返回false并重新将排列变成字典序最小的方式。
简单验证一下

#include<iostream>
#include<algorithm> 
using namespace std;
int a[10];
int main()
{
	for(int i=1;i<=5;i++)
	{
		a[i]=i;
	}	
	do
	{
		for(int i=1;i<=5;i++)
		{
			cout<<a[i]<<' ';
		}
		cout<<endl;
	}
	while(next_permutation(a+1,a+6));
	return 0;
}

通过这几行代码我们可以按字典序输出从1到5的全排列(太长了,中间省略QAQ):

1 2 3 4 5
1 2 3 5 4
1 2 4 3 5
1 2 4 5 3
……
1 5 4 3 2
2 1 3 4 5
……

5 4 3 1 2
5 4 3 2 1

可以看到,在输出字典序最大的排列后,程序就停了下来。现在我们修改代码使程序死循环,看看字典序最大时结果会如何变化。
我们将中间几行代码改为:

	while(1)
	{
		next_permutation(a+1,a+6);
		for(int i=1;i<=5;i++)
		{
			cout<<a[i]<<' ';
		}
		cout<<endl;
	}

看一下运行结果:

1 2 3 5 4
1 2 4 3 5
1 2 4 5 3
……
5 4 3 1 2
5 4 3 2 1
1 2 3 4 5
1 2 3 5 4
……
5 4 3 2 1
1 2 3 4 5
……
5 4 3 2 1
1 2 3 4 5
……
5 4 3 2 1
1 2 3 4 5
……
5 4 3 2 1
1 2 3 4 5
……

将两次运行结果对比,我们可以发现当next_permutation函数返回false,也就是字典序达到最大值时,函数就会将其变成字典序最小的排列形式,与前面所说一致。
枚举全排列的时间复杂度是O(n!),一般不能超过11个元素。

实战练习

例题1:全排列问题

这道题是深搜的模板题,如果不知道next_permutation的话,就只能傻傻的用递归写:

#include<iostream>
using namespace std;
const int N=10001;
int path[N],book[N];
int n;
void dfs(int u)
{
	if(u==n+1)
	{
		for(int i=1;i<=n;i++)
			printf("%5d",path[i]);
		cout<<endl;
		return;
	}
	for(int i=1;i<=n;i++)
	{
		if(!book[i])
		{
			path[u]=i;
			book[i]=1;
			dfs(u+1);
			book[i]=0;
		}				
	}
	
}
int main()
{
	cin>>n;
	dfs(1);
	return 0;
}

当初理解不了回溯,被虐的死去活来,而现在借助next_permutation,我们只需要简单的循环就能解决问题:

#include<iostream>
#include<algorithm> 
using namespace std;
const int N=1e5;
int a[N];
int n;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		a[i]=i;
	}	
	do
	{
		for(int i=1;i<=n;i++)
		{
			printf("%5d",a[i]);
		}
		cout<<endl;
	}
	while(next_permutation(a+1,a+n+1));
	return 0;
}


怎么样,感受到它的威力了吗?我们趁热打铁,看一下第二道例题:

例题2:火星人

是不是有点晕?这道题歪歪斜斜的每行都写着”火星人“三个字,我横竖睡不着,仔细看了半夜,才从字缝里看出字来,满本都写着两个字是”排列“!(手动滑稽)
用一句话概括题意,其实就是求从1到n的字典序全排列的第m个排列,直接用next_permutation即可:

#include<iostream>
#include<algorithm> 
using namespace std;
const int N=1e5;
int a[N];
int n,m;
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}	
	while(m--)
	{
		next_permutation(a+1,a+n+1);
		
	}
	for(int i=1;i<=n;i++)
	{
		cout<<a[i]<<' ';
	}
	cout<<endl;
	return 0;
}


举报

相关推荐

0 条评论