プログラムで総当たりしてみた

昨日の問題で、”OOPS!”AOIさんから以下のコメントを頂いた。


お茶休憩にmixiで発見!
あー、こういうの好きー。

俺も考えてみた・・・。

2つの組で1log下げるより(4log下がる)、3つの組で2log下げた方(8log下がる)
が効率よさそう・・・と思って、電卓計算・・・。

試行錯誤の結果、
2.0/(1.2-1.9/1.6)(1.3-1.8/1.4)(1.7/1.5-1.1)
が30万ちょっと超えた。

 多分組み合わせをプログラムして総当たりすると、
いいんだろうけど、それは、

mjhさんにおまかせ〜。^^;

おまかせされたので、プログラムを書いてみた。(笑)
明日はRubyKaigiに出かけるけど、気分的にきょうはJavaで書いたw


p1/(abs(p2-p3/p4) * abs(p5-p6/p7) * abs(p8-p9/p10))

で、求めた値の大きな上位10通りの組み合わせを求めてみた。MacBook Pro(Corei7 2.66GHz)で、実行時間は1.5秒ほど。
以下、実行結果。


RANKING#1 ... 335999.9999999977 : 2.0 / (abs(1.2-1.9/1.6) * abs(1.1-1.7/1.5) * abs(1.3-1.8/1.4)
RANKING#2 ... 335999.9999999977 : 2.0 / (abs(1.1-1.7/1.5) * abs(1.2-1.9/1.6) * abs(1.3-1.8/1.4)
RANKING#3 ... 335999.9999999976 : 2.0 / (abs(1.2-1.9/1.6) * abs(1.3-1.8/1.4) * abs(1.1-1.7/1.5)
RANKING#4 ... 335999.9999999976 : 2.0 / (abs(1.1-1.7/1.5) * abs(1.3-1.8/1.4) * abs(1.2-1.9/1.6)
RANKING#5 ... 335999.9999999976 : 2.0 / (abs(1.3-1.8/1.4) * abs(1.1-1.7/1.5) * abs(1.2-1.9/1.6)
RANKING#6 ... 335999.9999999976 : 2.0 / (abs(1.3-1.8/1.4) * abs(1.2-1.9/1.6) * abs(1.1-1.7/1.5)
RANKING#7 ... 311999.9999999978 : 2.0 / (abs(1.2-1.9/1.6) * abs(1.1-1.7/1.5) * abs(1.4-1.8/1.3)
RANKING#8 ... 311999.9999999978 : 2.0 / (abs(1.1-1.7/1.5) * abs(1.2-1.9/1.6) * abs(1.4-1.8/1.3)
RANKING#9 ... 311999.9999999978 : 2.0 / (abs(1.4-1.8/1.3) * abs(1.1-1.7/1.5) * abs(1.2-1.9/1.6)
RANKING#10 ... 311999.9999999978 : 2.0 / (abs(1.1-1.7/1.5) * abs(1.4-1.8/1.3) * abs(1.2-1.9/1.6)

”OOPS!”AOIさんの試行錯誤結果がトップに出てきて驚いた。すごい!!
最初の1log**4法と今回の2log**3法以外でも何か良い方法があるか引き続き考えてみたい。
以下、プログラムリスト。

import java.lang.*;
import java.util.*;

public class Puzzle01 {
    protected static final int RANKING = 10;

    public static void main(String[] args) {

        final double[] data = new double[] { 1.1 , 1.2 , 1.3 , 1.4 , 1.5 , 1.6 , 1.7 , 1.8 , 1.9 , 2.0 };
        final TopN topn= new TopN(RANKING);

        new Combinator(data.length,new CombinationHandler() {
            public void execute(int[] indeces) {
                double result = calc(data,indeces);
                if (!(result == Double.POSITIVE_INFINITY || result == Double.NEGATIVE_INFINITY)) {
                    topn.update(result,indeces);
                }
            }
            private double calc(double[] data,int[] idx) {
                return data[idx[0]] / (Math.abs(data[idx[1]]-data[idx[2]]/data[idx[3]]) *
                        Math.abs(data[idx[4]]-data[idx[5]]/data[idx[6]]) *
                        Math.abs(data[idx[7]]-data[idx[8]]/data[idx[9]]));
            }
        }).doCombinate();

        for (int i=0 ; i<RANKING ; i++) {
            System.out.print("RANKING#"+(i+1)+" ... ");
            System.out.print(""+topn.getData(i)+"  : ");
            int[] ds = (int[])topn.getDescription(i);
            System.out.println(""+data[ds[0]]+
            " / (abs("+data[ds[1]]+"-"+data[ds[2]]+"/"+data[ds[3]]+")" +
            " * abs("+data[ds[4]]+"-"+data[ds[5]]+"/"+data[ds[6]]+")" +
            " * abs("+data[ds[7]]+"-"+data[ds[8]]+"/"+data[ds[9]]+")"
            );
        }

        System.out.println("End of execution...");
    }
}

class TopN {
    protected DataHolder[] dataList_;
    protected boolean sorted_;

    public TopN(int n) {
        dataList_ = new DataHolder[n];
        sorted_ = false;
    }    

    public void update(double value,Object description) {
        double minValue = Double.MAX_VALUE;
        int minIndex = -1;

        for (int i=0 ; i<dataList_.length ; i++) {
            if (dataList_[i] == null) {
                dataList_[i] = new DataHolder(value,description);
                return;
            }
            if (minValue > dataList_[i].data) {
                minValue = dataList_[i].data;
                minIndex = i;
            }
        }
        if (value > minValue) {
            dataList_[minIndex] = new DataHolder(value,description);
            sorted_ = false;
        }
    }

    public double getData(int rank) {
        sort();
        return dataList_[rank].data;
    }

    public Object getDescription(int rank) {
        sort();
        return dataList_[rank].description;
    }

    protected void sort() {
        if (sorted_ == false) {
            Arrays.sort(dataList_,new Comparator<DataHolder>() {
                public int compare(DataHolder d1,DataHolder d2) {
                    double data1 = d1.data;
                    double data2 = d2.data;
                    if (data1 < data2) {
                        return 1;
                    } else
                    if (data1 > data2) {
                        return -1;
                    } else {
                        return 0;
                    }
                }
            });
            sorted_ = true;
        }    
    }
    
    protected class DataHolder {
        public double data;
        public Object description;

        public DataHolder(double data,Object description) {
            this.data = data;
            this.description = description;
        }
    }
}

interface CombinationHandler {
    public void execute(int[] indeces);
}

class Combinator {
    protected int digit_;
    protected CombinationHandler handler_;

    public Combinator(int digit,CombinationHandler handler) {
        digit_ = digit;
        handler_ = handler;
    }

    public void doCombinate() {
        for (int i=0 ; i<digit_ ; i++) {
            long[] context = new long[1];
            context[0] = (1<<i);
            calcCombination(context,digit_-1);
        }
    }

    protected void calcCombination(long[] context,int remain) {
        long markedPoints = getMarkedPoints(context);
        if (remain == 1) {
            for (int i=0 ; i<digit_ ; i++) {
                if ((markedPoints & (1<<i)) == 0) {
                    handler_.execute(makeIndeces(generateContext(context,i)));
                    break;
                }
            }
        } else {
            for (int i=0 ; i<digit_ ; i++) {
                if ((markedPoints & (1<<i)) == 0) {
                    calcCombination(generateContext(context,i),remain-1);
                }
            }
        }
    }

    protected long getMarkedPoints(long[] dataset) {
        long points = 0;
        for (long data : dataset) {
            points |= data;
        }
        return points;
    }

    protected int[] makeIndeces(long[] context) {
        int[] indeces = new int[context.length];
        for (int i=0 ; i<context.length ; i++) {
            for (int pos=0 ; pos<context.length ; pos++) {
                if (context[i] == (1<<pos)) {
                    indeces[i] = pos;
                    break;
                }
            }
        }
        return indeces;
    }

    protected long[] generateContext(long[] context,int value) {
        long[] newContext = new long[context.length + 1];
        for (int i=0 ; i<context.length ; i++) {
            newContext[i] = context[i];
        }
        newContext[context.length] = 1<<value;
        return newContext;
    }
}