1. 程式人生 > >1038. Recover the Smallest Number (30)好題

1038. Recover the Smallest Number (30)好題

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.

Input Specification:

Each input file contains one test case. Each case gives a positive integer N (<=10000) followed by N number segments. Each segment contains a non-negative integer of no more than 8 digits. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print the smallest number in one line. Do not output leading zeros.

Sample Input:
5 32 321 3214 0229 87
Sample Output:
22932132143287
     一道看起來很簡單,寫起來有點痛苦,最後解法比較有趣的題目。據說是一道面試題的改編。      題目給你一些數字的片段(number segments),所以應當用string儲存而不是int,希望拼接之後能拼出的最小的數字,這是一道很神奇的題目,我分類討論分了很多,最後突然發現它的最終解法無比簡潔。      其實就是一個序的關係,所有的組合有n!種,(像"所謂組出最小數其實是獲得字典序最小的拼接方式"這種廢話我就不說了)。假設我們獲得了其中的一個組合,然後又兩個相鄰的數字片段a,b。然後我們就要想,把a和b交換能不能使整個序列變小呢?這個問題的其實等價於b+a 是否小於a+b(此處"+"為連線符),也就是說對於這樣一個序列,如果某兩個相鄰的元素之間發生交換可以使得整個序列的值變小,我們就應該堅決的交換啊,所以這裡定義一個新的序,用<<來表示,若a+b < b + a 則a應當在b前面,即a << b。然後呢,這種序是滿足傳遞性的若a<<b ,b << c,則a<<c,所以迭代到最後,我們就會獲得一個任何兩個相鄰元素都不能交換的局面,也就是所謂的答案。

     這樣一來我們的演算法就有了,比較每兩個相鄰的元素,如果交換可以使得整個序列變大,就交換之,直到最後沒有任何兩個值之間能進行交換,啊,這不就是傳說中的Bubble_Sort嗎,真是一個令人激動的結論啊。對序列按照之前定義的序進行排序,如此就好了。
# include <cstdio>
# include <iostream>
# include <string>
using namespace std;

const int _size = 10000;
string num[_size];
bool cmp(const string& a,const string& b){return a + b< b + a;}
int main()
{
  int n,i;
  cin >> n;
  for (i=0;i<n;i++)
     cin >> num[i];
  sort(num,num+n,cmp);
  string out;
  for (i=0;i<n;i++)
      out += num[i];
  for (i=0;i<out.size()&&out[i]=='0';i++);
  if (i==out.size())
      printf("0");
  else 
      printf("%s",out.c_str()+i);
  printf("\n");
  return 0;
}