【HDOJ】1027 Ignatius and the Princess II
这道题目最开始完全不懂,后来百度了一下,原来是字典序。而且还是组合数学里的东西。看字典序的算法看了半天才搞清楚,自己仔细想了想,确实也是那么回事儿。对于长度为n的数组a,算法如下:
(1)从右向左扫描,找到满足a[i]<a[i+1]的第一个i,也就是i = max{i|a[i]<a[i+1]},同时也意味着a[i+1]~a[n]是升序;
(2)从右向左扫描,找到满足a[j]>a[i]的第一个j,也就是j = max{j|a[j]>a[i]},a[j]也是满足大于a[i]的最小数;
(3)交换a[i]与a[j];
(4)将a[j+1]与a[n]间的数字逆转。
直接实现算法:
1 #include <stdio.h> 2 3 #define MAXNUM 1005 4 5 int array[MAXNUM]; 6 7 void chgonce(int n) { 8 int i, j, k, tmp; 9 10 i = n-1; 11 while (i && array[i]>array[i+1]) 12 i--; 13 14 k = 0; 15 j = n; 16 while (j && array[j]<array[i]) 17 j--; 18 19 if (array[j] > array[i]) 20 k = 1; 21 22 if (k) { 23 tmp = array[j]; 24 array[j] = array[i]; 25 array[i] = tmp; 26 27 // reverse 28 for (k=i+1; k*2<=n+i+1; ++k) { 29 tmp = array[k]; 30 array[k] = array[n+i+1-k]; 31 array[n+i+1-k] = tmp; 32 } 33 } 34 } 35 36 int main() { 37 int n, m; 38 int i, k; 39 40 while (scanf("%d %d", &n, &m) != EOF) { 41 for (i=1; i<=n; ++i) { 42 array[i] = i; 43 } 44 k = 1; 45 while (k<m) { 46 chgonce(n); 47 ++k; 48 } 49 for (i=1; i<=n; ++i) { 50 if (i==1) 51 printf("%d", array[i]); 52 else 53 printf(" %d", array[i]); 54 } 55 printf("\n"); 56 } 57 58 return 0; 59 }
STL的next_permutation也可以直接实现:
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 #define MAXNUM 1005 6 7 int array[MAXNUM]; 8 9 int main() { 10 int n, m, k; 11 12 while (cin>>n>>m) { 13 for (int i=0; i<n; ++i) 14 array[i] = i+1; 15 k = 1; 16 while (k++<m) 17 next_permutation(array, array+n); 18 cout <<array[0]; 19 for (int i=1; i<n; ++i) 20 cout <<" "<<array[i]; 21 cout <<endl; 22 } 23 return 0; 24 }