正整數連接最小算法

題目:

有n個正整數數,將他們按十進制按某種順序組成一個更大的整數,求最小的這個整數。

舉例,有數字32和321,連接成32132後最小。

又舉例,有數字1876,98,21,4,211連接成1876 211 21 4 98是最小的。


解決思路:

1.用揹包動態規劃的思想很容易。因爲ABCD最小的必要條件ABC最小,時間複雜度是0(n*n*k)


2.第二種解決方法要先做一個數學證明。

首先,規定一種比較規則:a->b表示ab<ba成立,記作規則一。

其次:需要證明一個定律。

定律一:n個正整數的最小組合

X1X2X3....Xn中,Xi->Xj(其中i<j)一定成立。

證明這個定律我們可以用反證法。

假設最小的組合中存在Xj->Xi(其中i<j),即XiXj>XjXi那麼要證明假設不成立我們只需要證明Xi...Xj不是最小的即可。

可以分兩種情況:

第一種:j=i+1。很顯然,XjXi比XiXj更小,這種情況假設不成立。

第二種:j>i+1。即Xi Xi+1...Xj-1 Xj。爲了方便,我們把中間的記作y,把Xi記作a,把Xj記作b。也就是所,我們必須證明ayb不是最小的。

假如ayb是最小的,那肯定存在ay<ya和yb<by。設a的位數是m,y的位數是n,b的位數是k。那麼

1.ay<ya   ==>   a*10^n+y<y*10^m+a   ==>   a*(10^n-1)/(10^m-1) < y 

2.yb<by   ==>   y*10^k+b<b*10^n+y     ==>   y<b*(10^n-1)/(10^k-1)

3.綜合1和2可以得出a*(10^k-1)<b*(10^m-1)  ==>  a*10^k+b < b*10^m+a  ==> ab < ba

即XiXj<XjXi,很顯然與條件矛盾,所以假設不成立。


綜上所述,假設不成立,原命題成真。

有了定律一,其實我們還可以得到另一個定律。

定律二:當ab<ba且bc<cb時,ac<ca一定成立。

這裏,我們有三個正整數,a,b,c。其中a->b且b->c。

因爲我們可以得到個最小的組合。

x1x2x3,且x1->x2,x2->x3且x1->x3。加入b是x1,那麼a就沒得選了,如果b是x3,那麼c就沒得選了。所以b肯定是x2,同理,a必須是x1,c必須是x3。即如下:

abc

故a->c成立。即命題成立。


至此,我們有了一下結論:

給定的n個正整數,我們可以通過規則一將其排序,排序後將它們連起來就是最小組合了。時間複雜度0(k*n*logn)


這裏,我爲什麼要囉嗦地強調定律二呢?因爲沒有定律二,我們就沒辦法按照規則一進行排序。

這裏有一片文章講述了定律一的證明,這裏採用的就是這篇文章的方法。

http://blog.csdn.net/cxllyg/article/details/7659525

這篇文章的問題就是開篇就講按照規則一排序,這是有一個問題,那就是在不知道定律二之前,根本就不知道規則一能不能排序!


另外有一篇文章有提到定律二,但說得太草率了。

http://blog.csdn.net/yysdsyl/article/details/4248537

如果A+B>=B+A,B+C>=C+B,則一定有:A+C>=C+A

誰能告訴我這個定律是怎麼證明的嗎?事實上,我花了很久的時間都沒法直接證明這個定律!


當然,感謝上面兩位大牛,在他們的基礎上,我纔算完美地解決了這個問題。

C++代碼:

//
//  MinConnect.h
//  test
//
//  Created by JiangHuifu on 14-6-1.
//  Copyright (c) 2014年 veger. All rights reserved.
//

#ifndef __test__MinConnect__
#define __test__MinConnect__

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;


class CMinConnect {
    vector<char*> datas;//所有的整數以字符串的方式存儲
private:
    void getData();//獲取數據,並將數字以十進制字符串的方式存儲起來
    void sort();//排序
    string getResult();//獲得結果
public:
    virtual ~CMinConnect();
    void play();//運行算法
    static bool cmp( char* &a, char* &b);//比較函數,如果ab<=ba則返回true,否則返回false
};

#endif /* defined(__test__MinConnect__) */

//
//  MinConnect.cpp
//  test
//
//  Created by JiangHuifu on 14-6-1.
//  Copyright (c) 2014年 veger. All rights reserved.
//

#include "MinConnect.h"
#include <sstream>
static inline unsigned int log10(unsigned int t){
    int i = 1;
    do{
        t/=10;
        i*=10;
    }while (t>0);
    return i/10;
}
void CMinConnect::play(){
    getData();//獲取數據,並將數字以十進制字符串的方式存儲起來
    sort();//排序
    cout<<getResult();//輸出結果
}
void CMinConnect::getData(){
    unsigned int k;
    unsigned int n = 1000;
    for (unsigned int i  = 0; i<n; i++) {
        k = abs(rand()%1000000+1);
        cout<<k<<endl;
        char* p = (char*)malloc(sizeof(char)*(1+log10(k)*10));
        if (p==NULL) {
            throw -1;
        }else{
            sprintf(p, "%d",k);
        }
        datas.push_back(p);
    }
}
void CMinConnect::sort(){
    std::__1::sort(datas.begin(), datas.end(), CMinConnect::cmp);
}
bool CMinConnect::cmp(char* &a, char* &b){//比較ab和ba大小的函數
    if (a==NULL || b==NULL) {//有必要,防止出錯
        return true;
    }
    char *p1=a,*p2=b;
    int flag = 3;
    while (flag > 0) {
        while (('\0' != *p1)&&('\0' != *p2)) {
            if (*p1 > *p2) {
                return false;
            }else if(*p1 < *p2){
                return true;
            }
            ++p1;
            ++p2;
        }
        if (NULL == p1 && NULL == p2) {
            flag -= 2;
        }else{
            flag -= 1;
            if (NULL == p1) {
                p1 = b;
            }
            if (NULL == p2) {
                p2 = a;
            }
        }
    }
    return true;
}
string CMinConnect::getResult(){
    ostringstream s;
    s<<"result is:";
    for (vector<char*>::iterator i = datas.begin(); i!=datas.end(); ++i) {
        s<<" "<<*i;
    }
    s<<endl;
    
    return s.str();
}
CMinConnect::~CMinConnect(){
    for (vector<char*>::iterator i = datas.begin(); i!=datas.end(); ++i) {
        free(*i);
        *i = NULL;
    }
    datas.clear();
}




發佈了18 篇原創文章 · 獲贊 1 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章