德•梅齊里亞克的法碼問題

德·梅齊里亞克的法碼問題The Weight Problem of Bachet de Meziriac 

    一位商人有一個40磅的砝碼,由於跌落在地而碎成4塊.後來,稱得每塊碎片的重量都是整磅數,而且可以用這4塊來稱從1至40磅之間的任意整數磅的重物.

    問這4塊砝碼碎片各重多少?

這是一個著名的初等數學問題,解決這樣的問題我們第一想到的辦法就是窮舉法。

假設: 4個碎片的重量分別爲整數a,b,c,d,那麼從1到40中的任意整數n都必然能被a,b,c,d的加減組合所表示。我們直觀的想到將a,b,c,d的所有加減組合全部列出來:

一個操作數:a?n     b?n    c?n    d?n

兩個操作數:a+b?n     a+c?n    a+d?n     b+c?n    b+d?n     c+d?n    b-a?n      c-a?n      c-b?n      …..

三個操作數:…..

很快我們就發現太複雜了,能不能有一種比較簡單的方式將可能的計算組合全部表示出來呢?

我們想到,對於a,b,c,d四個數來說,參加計算的數是從其中任選出來的,我們可以用4bit的0、1字符串來記錄對應的數是否參與計算,1表示參與,0表示不參與。

如0001表示只有a參與計算

這樣對應的計算組合就有

dcba

0001

0010

1111

二進制轉化爲10進制,一個循環就可以搞定。

同理,由於計算只能爲加減運算,且參與計算的數最多隻有4個,則參與計算的操作符最多爲3個,用和上述類似的方法將操作符的組合窮舉出來。

代碼:

public class T002 {

/**
* @author magic_wk
*/

//獲取參與操作數的參與數組
public static int[] getOp(int n){
int [] a=new int[4];
        int i=0;
while(n!=0){
a[i]=n%2;
n/=2;
i++;
}
return a;
}

//獲取參與計算的操作符數組
public static char[] getOpreater(int n){
char [] res=new char[3];
int i=0;
while(i<3){
res[i]=(n%2==0)?’+’:’-‘;
n/=2;
i++;
}
return res;
}

//計算表達式
public static int cal(int a,int b,int c,int d,int[] op,char[] opreater){
int res = 0;
switch (opreater[2]) {
case ‘+’:
res = d * op[3] + c * op[2];
break;
case ‘-‘:
res = d * op[3] – c * op[2];
break;
}
switch (opreater[1]) {
case ‘+’:
res = res + b * op[1];
break;
case ‘-‘:
res = res – b * op[1];
break;
}
switch (opreater[0]) {
case ‘+’:
res = res + a * op[0];
break;
case ‘-‘:
res = res – a * op[0];
break;
}
return res;
}

//檢查a,b,c,d的組合計算能否表示從1到40的任意數字
public static boolean check(int a,int b,int c,int d){
int[] op;
char[] opreater;
for(int i=1;i<=40;i++){
int f1=0;
for(int k=1;k<16;k++){
int f2=0;
op=getOp(k);
for(int j=0;j<8;j++){
opreater=getOpreater(j);
if(cal(a,b,c,d,op,opreater)==i){f2=1;break;}
}
if(f2==1){f1=1;break;}
}
if(f1==0)return false;
}
return true;
}


public static void main(String[] args) {
// TODO Auto-generated method stub
        for(int i=0;i<10;i++)
        for(int j=i+1;j<15;j++)
        for(int k=j+1;k<20;k++)
        if(check(i,j,k,40-i-j-k)){
        System.out.println(i+”, “+j+”, “+k+”, “+(40-i-j-k));
        return;
        }
        System.out.println(“no answer!”); 
}

}

最後結果爲:1, 3, 9, 27

点赞