组合数学(全排列)+DFS CSU 1563 Lexicography

 

题目传送门

 1 /*
 2     题意:求第K个全排列
 3     组合数学:首先,使用next_permutation 函数会超时,思路应该转变,
 4     摘抄网上的解法如下:
 5         假设第一位是a,不论a是什么数,axxxxxxxx一共有8!种选择。 
 6         297192 div 8! = 7,余14952,所以第一位是1-9中的第8个数,也就是8。 
 7         14952 div 7! = 2,余4872,所以第二位是3。 
 8         4872 div 6! = 6,余552,所以是第三位是1245679这七个数中的第7个,也就是 9。 
 9         552 div 5! = 4,余72,所以是124567中的第5个,也就是6。 
10         72 div 4! = 2,余24,所以是4。 
11         这时候就不用算了,因为24 = 4!,而剩下的数就是1257这4个,他们组成的排列的第 
12         24个必然是7521。
13     以上解法只符合没有重复的序列,但是思路一致,把除法改为减法,每一次更新之后的全排列的数量
14     即 Ann / Amm 的个数,可以用DFS实现
15 */
16 #include <cstdio>
17 #include <iostream>
18 #include <algorithm>
19 #include <stack>
20 #include <cmath>
21 #include <cstring>
22 #include <vector>
23 using namespace std;
24 
25 const int MAXN = 1e4 + 10;
26 const int INF = 0x3f3f3f3f;
27 char s[20];
28 int cnt[30];
29 int pos[20];
30 int len;
31 
32 long long fact(int x)
33 {
34     long long res = 1;
35     for (int i=1; i<=x; ++i)    res *= i;
36 
37     return res;
38 }
39 
40 long long f(int step)
41 {
42     long long res = fact (step);
43     for (int i=0; i<26; ++i)    if (cnt[i])    res /= fact (cnt[i]);
44 
45     return res;    
46 }
47 
48 void DFS(int step, long long k)
49 {
50     if (step == len)
51     {
52         for (int i=0; i<len; ++i)    printf ("%c", 'A' + pos[i]);
53         puts ("");    return ;
54     }
55 
56     for (int i=0; i<26; ++i)
57     {
58         if (cnt[i] == 0)    continue;
59         cnt[i]--;
60         long long tmp = f (len - step - 1);
61         if (tmp < k)    {k -= tmp;    cnt[i]++;}
62         else
63         {
64             pos[step] = i;
65             DFS (step+1, k);
66             return ;
67         }
68     }
69 }
70 
71 int main(void)        //CSU 1563 Lexicography
72 {
73     //freopen ("C.in", "r", stdin);
74 
75     long long k;
76     while (scanf ("%s%lld", &s, &k) == 2)
77     {
78         if (s[0] == '#' && k == 0)    break;
79 
80         len = strlen (s);
81         memset (pos, 0, sizeof (pos));
82         memset (cnt, 0, sizeof (cnt));
83         for (int i=0; i<len; ++i)    cnt[s[i]-'A']++;
84 
85         DFS (0, k);
86     }
87 
88     return 0;
89 }
90 
91 /*
92 MAC
93 PICC
94 IGNORE
95 */

附带给出求1~9无重复数字的第K个全排列的两种方法

 1 /*
 2     假设第一位是a,不论a是什么数,axxxxxxxx一共有8!种选择。 
 3     297192 div 8! = 7,余14952,所以第一位是1-9中的第8个数,也就是8。 
 4     14952 div 7! = 2,余4872,所以第二位是3。 
 5     4872 div 6! = 6,余552,所以是第三位是1245679这七个数中的第7个,也就是 9。 
 6     552 div 5! = 4,余72,所以是124567中的第5个,也就是6。 
 7     72 div 4! = 2,余24,所以是4。 
 8     这时候就不用算了,因为24 = 4!,而剩下的数就是1257这4个,他们组成的排列的第 
 9     24个必然是7521。 
10 */
11 #include <cstdio>
12 #include <iostream>
13 #include <algorithm>
14 #include <stack>
15 #include <cmath>
16 #include <cstring>
17 #include <vector>
18 using namespace std;
19 
20 const int MAXN = 1e4 + 10;
21 const int INF = 0x3f3f3f3f;
22 int num[11];
23 int ans[11];
24 int f[11];
25 
26 int main(void)
27 {
28     //freopen ("test_C.in", "r", stdin);
29 
30     int k;
31     while (scanf ("%d", &k) == 1)
32     {
33         f[0] = 1;
34         for (int i=1; i<=9; ++i)    {f[i] = f[i-1] * i;    num[i] = i;}
35 
36         int tot = 0;
37         int len = 9;
38         bool flag = false;
39         while (tot < len)
40         {
41             int pos = k / f[len-tot-1] + 1;
42             k %= f[len-tot-1];
43 
44             if (k == 0)    {pos--;    flag = true;}
45 
46             int t = 0;
47             for (int i=1; i<=9; ++i)
48             {
49                 if (num[i] != 0)
50                 {
51                     ++t;
52                     if (t == pos)
53                     {
54                         printf ("%d", num[i]);
55                         tot++;    num[i] = 0;    break;
56                     }
57                 }
58             }
59 
60             if (flag)
61             {
62                 for (int i=9; i>=1; --i)
63                 {
64                     if (num[i] != 0)    printf ("%d", num[i]);
65                 }
66                 break;
67             }
68         }
69         puts ("");
70     }
71     return 0;
72 }
73 
74 /*
75 839647521
76 */
1. 用上面的思路
 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <stack>
 5 #include <cmath>
 6 #include <cstring>
 7 #include <vector>
 8 using namespace std;
 9 
10 const int MAXN = 1e4 + 10;
11 const int INF = 0x3f3f3f3f;
12 int num[11];
13 int ans[11];
14 int f[11];
15 
16 int main(void)
17 {
18     //freopen ("test_C.in", "r", stdin);
19 
20     int k;
21     while (scanf ("%d", &k) == 1)
22     {
23         for (int i=1; i<=9; ++i)    num[i] = i;
24 
25         int len = 9;
26         long long cnt = 0;
27         do{
28             ++cnt;
29             if (cnt == k)    break;
30         }while (next_permutation (num+1, num+1+len));
31 
32         for (int i=1; i<=9; ++i)
33             printf ("%d", num[i]);
34         puts ("");
35     }
36     return 0;
37 }
38 
39 /*
40 839647521
41 */
2. 用next_permutation函数

 

posted @ 2015-04-21 14:37  Running_Time  阅读(291)  评论(0编辑  收藏  举报