天天看點

UVa 10905: Children's Game

這真是一道有趣的題目,不知道别人怎麼想,總之我覺得這題真的很有意思,值得一做。先附上題目:

There are lots of number games for children. These games are pretty easy to play but not so easy to make. We will discuss about an interesting game here. Each player will be given N positive integer. (S)He can make a big integer by appending those integers after one another. Such as if there are 4 integers as 123, 124, 56, 90 then the following integers can be made – 1231245690, 1241235690, 5612312490, 9012312456, 9056124123 etc. In fact 24 such integers can be made. But one thing is sure that 9056124123 is the largest possible integer which can be made.

You may think that it’s very easy to find out the answer but will it be easy for a child who has just got the idea of number?

Input

Each input starts with a positive integer N (≤ 50). In next lines there are N positive integers. Input is terminated by N = 0, which should not be processed.

Output

For each input set, you have to print the largest possible integer which can be made by appending all the N integers.

Sample Input Output for Sample Input

4

123 124 56 90

5

123 124 56 90 9

5

9 9 9 9 9

9056124123

99056124123

99999

讀完題目首先會想到找出所有N個數中首位最大的數排在第一個,如果有兩個數首位同時最大比較第二位,……如此下去會陷入複雜的讨論中,白費腦筋,我自己也同樣經曆了這樣一個過程。但回過頭來思考一下,就能想到更好的解決方案。

分析問題後可以将問題表述成如下形式:

給出N個正數,使用某種方法将這N個數排序,使其排序後所連成的一個數值最大。

那麼解決這個問題的關鍵就在于如何對這N個數進行排序?即排序的方法。

說到排序,我們可以使用qsort,但使用qsort的關鍵又在于其所調用的比較函數cmp,該函數cmp用于比較給出兩個正數時,哪個數應當放在左面,哪個放在右面。

下面思考cmp函數如何實作,可以這樣解決:對于兩個正數i,j,我們寫出其可以組合成的數,即ij和ji(注意這裡ij表示将i和j按順序寫出時所組成的一個更大的數),那麼比較ij和ji,就可以知道當我們将n個正數排序使之滿足題意時,若其中包含有i和j,那麼i一定出現在j的左邊或是j一定出現在i的左邊。

至此整個問題就分析完畢了,具體實作請參考我的解題代碼,如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <string>
#include <algorithm>
using namespace std;

char s[50][100];
int cmp(const void* i, const void* j)
{//判斷i與j均可選時先選哪個,這裡寫成比較函數供qsort調用
	char *a = (char *)i;
	char *b = (char *)j;
	char sak,sbk;
	int k,lena=strlen(a),lenb=strlen(b);
	for(k=0; k<lena+lenb; k++)
	{//循環判斷數字ij和數字ji各位是否相同
		if(k<lena) sak=a[k];
		else sak=b[k-lena];
		if(k<lenb) sbk=b[k];
		else sbk=a[k-lenb];
		if(sak!=sbk) break;
	}
	if(k==lena+lenb) return 0;	//ij與ji各位均相同,傳回0表示相等
	else
	{
		if(sak<sbk) return 1;	//ij的字典序較小,傳回1表示先選i再選j
		else return -1;
	}

}
int main()
{
	int N;
	while(cin >> N && N!=0)
	{
		for(int i=0; i<N; i++) cin >> s[i];
		qsort(s,N,sizeof(s[0]),cmp);
		for(int i=0; i<N; i++) cout << s[i]; cout << endl;
	}
	return 0;
}
           

這個算法的效率還不錯,AC用時0.109秒,排名211。

繼續閱讀