- 该题是luogu试炼场的2-11:T1
- 全排列类型的问题:全排列入门题
题目大意
- 给出一个n,表示关于n 的全排列事件;
- 给出一个m,表示经过m次后,排列的值是多少?
- 给出初始的排列状态;
题目分析
解题思路1
- 第一感觉,n是10000,深搜没戏;
- 但仔细分析一下,会发现题目中的m只有100,也就是说,只要找到第k个状态,能推出第 k+100 个状态,就搞定了!
- 想想10000!,感觉暴力排还是没戏!
- 看了一圈题解分析,发现只要 n次的操作就可以到达初始状态k,接下只是对m次的查找,时间似乎与 n 没什么太大关系66666
代码1:
//luogu1088:火星人
//原始想法:
//比较大胆的做法,直接暴力DFS,看题目就感觉不可能过
//10000!,稍微大一点的数据肯定不能过!
//认真地看了一遍大佬们的分析之后,发现自己太单纯了。。。。
//解题思路1:
//O(n),定向推进到 初始状态:不管第一个状态是“第几号全排列”,直接到达
//从这个初始状态,找到 +m 的状态,(m只有100),这个是完全没问题的。
#include<bits/stdc++.h>
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:
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 <bits/stdc++.h>
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]<a[x+1]) break;
}
for(y=n;y>=1;y--)//找到 x 位置后面,比他大的 y 位置
{
if(a[x]<a[y]) break;
}
swap(a[x],a[y]);
sort(a+1+x,a+1+n);//x+1:后面重新排序,
}
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
ss();
for(int i=1;i<=n;i++) printf("%d ",a[i]);
return 0;
}
解题思路3
代码3:
//luogu1088:火星人
//解法2:STL大法
#include<bits/stdc++.h>
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行代码,你值得拥有!