题目:Given a collection of number segments, you are supposed to recover the smallest number from them. For example, given {32, 321, 3214, 0229, 87}, we can recover many numbers such like 32-321-3214-0229-87 or 0229-32-87-321-3214 with respect to different orders of combinations of these segments, and the smallest number is 0229-321-3214-32-87.
先贴代码,后解释。
#include <iostream> #include <algorithm> #include <string> using namespace std; #define N 10000 struct S { string data; int valid; int rank; }; bool compare(S a, S b) { return a.data < b.data; } int main() { int n, i, j; S s[N]; string tmp; bool flag; while (cin >> n) { for (i = 0; i < n; i++) { cin >> tmp; s[i].valid = tmp.length(); s[i].data = "01234567"; for (j = 0; j < 8; j++) //把不足8为的数都循环补成8为,如32补为32323232 { s[i].data[j] = tmp[j % tmp.length()]; } } sort(s, s+n, compare); flag = 0; for (i = 0; i < n; i++) { for (j = 0; j < s[i].valid; j++) { if (flag) { cout << s[i].data[j]; } else if (s[i].data[j] != '0') { cout << s[i].data[j]; flag = 1; } } } if (!flag) cout << '0'; } return 0; }
我的解题思路也算比较清晰易懂,利用库函数sort排序的结果,唯有32,321,3214这样的数位置不对,经观察,这三个数的正确顺序和3232,3213,3214排序后的顺序一样,故代码中把所有数都补成8为,然后再用sort排序,得到的顺序就是结果要依次输出的顺序,只是别把补充的数输出来。
注意,该题有一个陷阱,开头的0不要输出,但是如果所有的数都是0,那么最后结果要输出一个0。
后来搜索网上解法,见 Sup_Heaven的专栏解法更妙,特把代码拷贝过来以便分享。#include<stdio.h> #include<string.h> #include<stdlib.h> int cmp(const void *m,const void *n){ char *a=(char *)m; char *b=(char *)n; char tmpa[20],tmpb[20]; strcpy(tmpa,a); strcpy(tmpb,b); strcat(tmpa,b); strcat(tmpb,a); return strcmp(tmpa,tmpb); } char str[10005][10]; int main(){ int i,j,n; scanf("%d",&n); for(i=0;i<n;i++){ scanf("%s",str[i]); } qsort(str,n,10*sizeof(char),cmp); int flag=0; for(i=0;i<n;i++){ for(j=0;str[i][j]!='';j++){ if(flag==0&&str[i][j]=='0'); else {flag=1;printf("%c",str[i][j]);} } } if(flag==0) printf("0");//如果所有段都为零,那么必须输出一个零 printf("n"); return 0; }该算法的核心在与compare函数,比较两个数,如3214和87,那么比较一下321487和874214,于是把哪个数放在前面能使得到的数最小便一目了然。