luogu1088:火星人:深搜/STL大法

题目连接

  • 该题是luogu试炼场的2-11:T1
  • 全排列类型的问题:全排列入门题

题目大意

  1. 给出一个n,表示关于n 的全排列事件;
  2. 给出一个m,表示经过m次后,排列的值是多少?
  3. 给出初始的排列状态;

题目分析

  • 看题目会大意会晕,但题目本身不难理解:
  • 给出关于 n 的当前的排列状态,求后面第m个状态。
  • 解题思路1:暴力DFS思维
  • 解题思路2:数位观察与分析
  • 解题思路3:STL大法
  • 解题思路4:神仙思路


解题思路1

  1. 第一感觉,n是10000,深搜没戏;
  2. 但仔细分析一下,会发现题目中的m只有100,也就是说,只要找到第k个状态,能推出第 k+100 个状态,就搞定了!
  3. 想想10000!,感觉暴力排还是没戏!
  4. 看了一圈题解分析,发现只要 n次的操作就可以到达初始状态k,接下只是对m次的查找,时间似乎与 n 没什么太大关系66666

代码1:

  • 手写dfs
//luogu1088:火星人 

//原始想法: 
//比较大胆的做法,直接暴力DFS,看题目就感觉不可能过 
//10000!,稍微大一点的数据肯定不能过!
//认真地看了一遍大佬们的分析之后,发现自己太单纯了。。。。 

//解题思路1:
//O(n),定向推进到 初始状态:不管第一个状态是“第几号全排列”,直接到达
//从这个初始状态,找到 +m 的状态,(m只有100),这个是完全没问题的。 

#include
using namespace std;

int a[10005],b[10005];
int n,m;
int ff=0;//ff=0,表示推进初始状态,ff=1表示从 初始状态+m 寻找最终状态 

void dfs(int x)//当前是第 x 个状态 
{
	
	if(x>n)//已经过了初始状态,进入查找+m 
	{
		ff++;//往 m 出发,计数 
		
		if(ff>m)//找到了:输出,结束 
		{
			for(int i=1;i<=n;i++) printf("%d ",a[i]);
			exit(0);
		}
	}
	
	//标准全排列:直接查找到外星人状态
	for(int i=1;i<=n;i++)
	{
		if(ff==0) i=a[x];//初始状态ing,每个值都是定的 
		
		//过了初始状态,i值才动 
		if(b[i]==0)
		{
			b[i]=1;
			a[x]=i;
			dfs(x+1);
			b[i]=0;
		}
	} 
}

int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	
	dfs(1);
	
	return 0;
}


解题思路 2

  • 简单的数位分析方法,稳一波:
  1. 从后往前观察,发现一个类似逆序对的思维;
  2. 当前的值和位置是有相关关系的,观察以下操作:
  • 观察1:
    1 2 3 (4 5) ==> 1 2 3 (5 4)
    分析:对于x位置(a[4]=4)而言,必须 在[x+1,n]的位置中,有比a[x]大的值,才能够步数增加,实现更新。
  • 观察2:
    1 4 (5 3 2) 括号内的三个数字都没有+1调动的意义
  • 观察3:
    1(4 5 3 2 ) 括号内 a[2]=4,可以与 a[3]=5进行交换,但步数+1的状态应该如下:1(5 4 2 3 )
    所以操作步骤1:a[2] 与 a[3] 交换
    步骤2:a[3]之后的值必须重新排序,才能实现步数+1;

代码2:

  • 数学分析
//luogu1088:火星人 

//数位分析法:

#include 
using namespace std;
int a[10005]; 
int i,j,k,m,n,t;

void ss()
{
	while(m--)//当前状态往前走 m 格 
	{
		int x,y; 
		for(x=n-1;x>=1;x--) //找到可以后移的位置 x
		{
			if(a[x]=1;y--)//找到 x 位置后面,比他大的 y 位置 
		{
			if(a[x]


解题思路3

  • 介绍STL里一个好用的函数:next_permutation(a+1,a+1+n)

代码3:

  • STL大法好!
//luogu1088:火星人 
 
//解法2:STL大法 

#include
using namespace std;

int a[10005];
int n,m;

int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	
	for(int i=1;i<=m;i++)//查找 m 次,下一个全排列 
		next_permutation(a+1,a+1+n);
		
	for(int i=1;i<=n;i++) printf("%d ",a[i]);
	
	return 0;
}


神仙的思路4

推荐一个大佬的神仙思路:27行代码,你值得拥有!


你可能感兴趣的:(题解,深搜,题表,luogu,大礼包,luogu1088,火星人)