vijosP1092 全排列

vijosP1092 全排列

链接:https://vijos.org/p/1092

【思路】

  数学+搜索。

  根据序号依次确定每一个数。

  首先我们可以把未选的数看作一个可选择集合,其次把寻找过程看作一棵树上的操作,如果有n个数我们已经确定了d个数,那么无论第d+1个数为多少以当前可选择集合中的任意一个数为根的子树的大小为(n-d-1)! 由此我们可以根据序号继续搜索。

  注意:选择k的含义为选择了当前可选择集合中第k小的数。

  详见代码

【代码】

 1 #include<iostream>
 2 #include<cstdlib>
 3 using namespace std;
 4 
 5 typedef long long LL;
 6 int n;
 7 LL m;
 8 int A[25];
 9 int vis[25];
10 
11 void dfs(int d,LL num) {
12     if(d==n) {
13         for(int i=0;i<d;i++) cout<<A[i]<<" ";
14         exit(0);
15     }
16     LL tmp=1;
17     for(int i=1;i<=(n-d-1);i++) tmp *= i;
18     for(int k=1;k<=n;k++)
19       if((k-1)*tmp<=num && num<=k*tmp) {
20           int cnt=0; int i;
21           for(i=1;i<=n;i++) if(!vis[i]) if(++cnt==k) break;
22           vis[i]=1; A[d]=i;
23           dfs(d+1,num-(k-1)*tmp);
24       }
25 }
26 
27 int main() {
28     cin>>n>>m;
29     dfs(0,m);
30     return 0;
31 } 

   注:本题与紫书P323 Password一题类似。

原文地址:https://www.cnblogs.com/lidaxin/p/4874857.html