[Project Euler] Problem 24
2011-03-07 21:37
330 查看
A permutation is an ordered arrangement of objects. For example, 3124 is one possible permutation of the digits 1, 2, 3 and 4. If all of the permutations are listed numerically or alphabetically, we call it lexicographic order. The lexicographic permutations of 0, 1 and 2 are:
012 021 102 120 201 210
What is the millionth lexicographic permutation of the digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9?
对 0123456789 作全变换,按由小到大排列,第1000,000个数是那个?
我们先来看看数字少的情况。
就拿上面的012来说吧
我们赋予每一位一个权值
0 1 2
2! 1! 0
我们交换0和1,然后对后两位由小到大排序,102是第3小排列,比第1小排列增加了2!
交换0和2,然后对后两位由小到大排序,201位于第5小排列,比第1位增加了2!×2
我们来看看第6小排列,比第一小排列增加了5
而 5 = 2×2! + 1×1!
我们先把第1个与位于它后面2位的数字交换,变为 210,然后把第一位数字之后的数字排序 变为 201,这样就增加了4
然后把第第二位与位于它后面1位的数字交换,变为201,再把第二位数字后面的数字排序,变为210,这样就增加了5,既第6小排列
我们再来看看四个数字的
0 1 2 3
3! 2! 1! 0
我们来找第23个排列,要比第1个排列大22
22 = 3×3! + 2×2!
按照上面的思路
先把第一位和它后面3位的数字交换,变为 3120, 然后把第一位之后的数排序 为 3012 这样就增加了 3×3!
再把第二位和它后面2位的数字交换,再排序,变为 3201,就是最后结果了
所以我们要找0123456789的1000,000位也可以按照这样的思路,增加999,999就是
0 1 2 3 4 5 6 7 8 9
9! 8! 7! 6! 5! 4! 3! 2! 1! 0
2 6 6 2 5 1 2 1 1
第3排就是该位和它要交换的位差的位数
我们用编程来看看这一过程
#include <iostream>
#include <vector>
#include <algorithm>
usingnamespace std;
int main(){
int factorial[9];
int sign[9];
int mul =1;
int sum =999999;
int tmp;
vector<int>out;
for(int i=0; i<10; i++){
out.push_back(i);
}
for(int i=1; i<10; i++){
mul = mul*i;
factorial[9-i] = mul;
}
for(int i=0; i<9; i++){
sign[i] = sum/factorial[i];
sum -= sign[i]*factorial[i];
}
for(int i =0; i<9; i++){
cout << i <<'\t'<< sign[i] <<'\t'<< factorial[i] << endl;
}
cout << endl;
for(int i=0; i<9; i++){
tmp =out[i];
out[i] =out[sign[i]+i];
out[sign[i]+i] = tmp;
sort(out.begin()+i+1,out.end());
for(int j=0; j<10; j++){
cout <<out[j];
}
cout << endl;
}
return0;
}
前面横着的是我们得到的那张表。中间是要交换的位数,后面是权值。
由于最后一位9对应的权值和要移的位数始终为0,所以没有列出
下面是每次调整排序后的结果
最后一行就是最后的结果
012 021 102 120 201 210
What is the millionth lexicographic permutation of the digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9?
对 0123456789 作全变换,按由小到大排列,第1000,000个数是那个?
我们先来看看数字少的情况。
就拿上面的012来说吧
我们赋予每一位一个权值
0 1 2
2! 1! 0
我们交换0和1,然后对后两位由小到大排序,102是第3小排列,比第1小排列增加了2!
交换0和2,然后对后两位由小到大排序,201位于第5小排列,比第1位增加了2!×2
我们来看看第6小排列,比第一小排列增加了5
而 5 = 2×2! + 1×1!
我们先把第1个与位于它后面2位的数字交换,变为 210,然后把第一位数字之后的数字排序 变为 201,这样就增加了4
然后把第第二位与位于它后面1位的数字交换,变为201,再把第二位数字后面的数字排序,变为210,这样就增加了5,既第6小排列
我们再来看看四个数字的
0 1 2 3
3! 2! 1! 0
我们来找第23个排列,要比第1个排列大22
22 = 3×3! + 2×2!
按照上面的思路
先把第一位和它后面3位的数字交换,变为 3120, 然后把第一位之后的数排序 为 3012 这样就增加了 3×3!
再把第二位和它后面2位的数字交换,再排序,变为 3201,就是最后结果了
所以我们要找0123456789的1000,000位也可以按照这样的思路,增加999,999就是
0 1 2 3 4 5 6 7 8 9
9! 8! 7! 6! 5! 4! 3! 2! 1! 0
2 6 6 2 5 1 2 1 1
第3排就是该位和它要交换的位差的位数
我们用编程来看看这一过程
#include <iostream>
#include <vector>
#include <algorithm>
usingnamespace std;
int main(){
int factorial[9];
int sign[9];
int mul =1;
int sum =999999;
int tmp;
vector<int>out;
for(int i=0; i<10; i++){
out.push_back(i);
}
for(int i=1; i<10; i++){
mul = mul*i;
factorial[9-i] = mul;
}
for(int i=0; i<9; i++){
sign[i] = sum/factorial[i];
sum -= sign[i]*factorial[i];
}
for(int i =0; i<9; i++){
cout << i <<'\t'<< sign[i] <<'\t'<< factorial[i] << endl;
}
cout << endl;
for(int i=0; i<9; i++){
tmp =out[i];
out[i] =out[sign[i]+i];
out[sign[i]+i] = tmp;
sort(out.begin()+i+1,out.end());
for(int j=0; j<10; j++){
cout <<out[j];
}
cout << endl;
}
return0;
}
前面横着的是我们得到的那张表。中间是要交换的位数,后面是权值。
由于最后一位9对应的权值和要移的位数始终为0,所以没有列出
下面是每次调整排序后的结果
最后一行就是最后的结果
相关文章推荐
- Project Euler:Problem 24 Lexicographic permutations
- Project Euler__problem 3
- Project Euler - Problem 6
- Project Euler – Problem 22
- [Project Euler] Problem 48
- Project Euler:Problem 42 Coded triangle numbers
- [Project Euler] Problem 57
- Project Euler:Problem 68 Magic 5-gon ring
- Project Euler:Problem 78 Coin partitions
- 欧拉项目(Project Euler)Problem 1
- 【Project Euler】【Problem 7】10001st prime
- Problem 24 Lexicographic permutations (全排列)
- Project Euler:Problem 28 Number spiral diagonals
- [Project Euler]加入欧拉 Problem3
- [Project Euler] Problem 13
- [Project Euler] Problem 25
- Project Euler Problem 24
- Project Euler__problem 5
- Project Euler:Problem 55 Lychrel numbers
- Project Euler – Problem 23