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一题类似。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值