十個正整數,任意兩數之差不相同,求其中最大數的最小值。如果是任意有限個正整數呢?
該問題是一個非常複雜的組合數學問題,可轉化為運籌學中的整數規劃問題。以下會看到,轉化為整數規劃問題,光是約束條件的描述也是挺複雜的。目標值的最小化是線性的,但約束條件的方程是非線性的。
設任意n個正整數
依小到大排列,即
任意兩數之差互不相同,使
取最小值。
為簡化起見,可設
, 以下會看到,只有
時,序列可取等號,
時均不能取等號,即序列 {
} 是嚴格單調遞增的。可將所有相差數排列成如下三角形(灰色部分):
因為要求任意兩個差數各不相同,即灰色三角形共
個差數各不相同。因此:
第一列數(代表相鄰兩個正整數之差)彼此互不相同。
第二列數(代表相隔兩位的兩個正整數之差)與第一列數互不相同,先按同一行進行比較,有
。因為
因此得出
,即
,從相隔一行比較,有:
,即
,因
, 故
, 得出
,兩者結合,得出
,即序列 {
} 是嚴格單調遞增的(對於
)。
那麼如果第一列和第二列相隔兩行,相隔三行,相隔m進行比較呢?更進一步,第
列和第
列相隔
行進行比較呢?如何描述各相差數互不相同的約束方程呢?
第
列第
行的數為:
第
列第
行的數為:
需滿足:
(
)
將不等號變為:
, 或
該問題的數學描述為:
為正整數。
這是一個約束條件為非線性的整數規劃問題,約束方程有
個。
看上去是一個典型的NP問題,當
較大時,是很難在多項式時間內獲得最優解的,
較小時可以透過列舉法獲得最優解。
對
較小時可以作如下分析:
1。
時,只有一個差數 ,沒有可比較的差數,因此可取
2。
時,可取 {
}={
}或{
}, 得到三個差數
或
均不同,而且是最小的三個差數,因此
為最優解
3。
時,若以 {
}={
}或{
}為基數推算
只能得出
6個差數(灰色標註)如下:
但
不是最優解,取 {
}={
} 即
才是最優解。
差數如下:
這六個差數以小到大排列正好是
, 是六個最小的差數,因此
是最優解。這說明如果
是n個正整數的最優解,以此為基礎推算的
不能保證
是n+1個正整數的最優解,這是需要特別注意的。
4。
時,取 {
}={
} 即
是最優解。
可以發現,隨著
的增大,差數按順序排列不再是連續的。上述10個差數從1到12,當中8和10沒有出現。透過電腦計算,對於
應該還是能推算出
的最優解。
對於
下面是按未出現相差數的最小者優先考慮的原則,得到的一個近似解
感謝知友【田宮水口鉗子】和【rice0208】提供的反例,後者給出的解(如下圖)
似乎是最優解的。
對較大的正整數
,尋求最優解是很困難的。因為該問題等同於NP問題,是很難在多項式時間內找到最優解的。如果能有演算法在時間複雜度
(
為某正整數)找到最優解,那就解決了NP問題,這可是世界級數學難題。
補充資料:
可以給出該問題解的一個上界。取
, 即
, 或者
, 則
是最優解的一個上界。因為 如果
是問題的一個可行解,其形成的所有差數均互不相同,最大差數為
, 而
能確保新出現的差數均大於已經出現的差數。新出現差數的最小值為
, 因此
是一個可行解,也就是最優解的一個上界。
這個可行解是很粗糙的,這裡給出該問題一個近似解的演算法,比上界
要好許多。以上面
的解為例,闡述如何從
推算到
:
將可行解序列 {
}形成的差 (上面灰色三角形部分)共45個數以小到大排列如下,並標記為藍色:
我們看到,1到55之間,未出現的差數有十個:{
}
近似解演算法的思路是:從這十個未出現差數中依小到大進行試用,36是首選,即
, 檢查新出現的差數是否與已出現的差數中任何一個重複,若有重複,則棄用,選擇下一個數
, 依次進行,直到選擇某個數不出現重複為止。假如試用這十個數均會出現重複數,則只能選擇可行解
。
經驗證,取
是可行的,於是確定
是一個近似解。比上界
更小。序列如下:
該演算法可以針對n很大時無法獲得最優解的情況下,能獲得一個較好的近似解。
我有一個c++演算法,用窮舉,但是太笨了,計算量非常大,我的電腦跑不過來。希望有大神可以來指點,或者給出更好的演算法。
#include
using namespace std;
bool bijiao(int a[]);
int main ()
{
int a[10];
int i;
for(a[0]=10;;a[0]++)
for(a[1]=9;a[1] for(a[2]=8;a[2] for(a[3]=7;a[3] for(a[4]=6;a[4] for(a[5]=5;a[5] for(a[6]=4;a[6] for(a[7]=3;a[7] for(a[8]=2;a[8] for(a[9]=1;a[9] { if(bijiao(a)) { cout<<“哈哈”< for(i=9;i>=0;i——) cout< return 0; }