Java、915 * 0.75 = 686.25
import java.util.*;class E implements Comparable<E>{static
int n,m,t,u;byte[]a;int k=2,b,d;E(){a=new byte[5];a[1]=13;}E(E
x){a=Arrays.copyOf(x.a,n+1);k=x.k;d=x.d;b=x.b;}int
g(int x){return(a[x]+1)%3-1;}void s(int x,int y){a[x]=(byte)(a[x]/3*3+(y+3)%3);}void
S(int x,int y){a[x]=(byte)(a[x]%3+(y+3)*3);}E
w(int x){if(g(k)==-x)return null;E e=new E(this);e.s(k,x);e.S(e.k++,x);for(m=0;++m<k;)if(k%m<1){u=e.a[m]/3-3+x;if(u==(k<9?2:4)*x)return
null;e.S(m,u);if(u==3*x){e.b++;if(k+m<=n){if(e.g(k+m)==x)return
null;e.s(k+m,-x);}}}return e;}public int compareTo(E o){m=d-o.d+(b-o.b)/60+(o.k-k)/150;return
m==0?o.k-k:m;}public static void main(String[]a){n=Integer.valueOf(a[0]);Queue<E>q=new PriorityQueue<>();q.add(new
E());for(;;){E x=q.remove(),y;if(x.k>n){for(t=0;++t<x.k;)System.out.print((x.g(t)+1)/2);return;}t=x.g(x.k<9?1:x.k%9==0?x.k/9:x.k%9);y=x.w(t);if(y!=null)q.add(y);y=x.w(-t);if(y!=null){y.d++;q.add(y);}}}}
入力はコマンドライン引数として取得されます。
これは、ほとんどすべての可能性を試行します(唯一の制限は、最初の8ステップが-1..1内でのみ行われることです)。
私の(かなり高速な)コンピューターで1秒以内に2000から4000までの問題を解決します。大きい数値にはより多くのRAMが必要です。8GB以内で解決した最大の入力は5023で、約30秒かかりました。
ボーナスに必要な2000ステップのソリューションの10進数表現:
67629177464446960798008264442022667063957880432486338092706841703491740570274032860458934082821213021464065304260003487277917407152662394728833698812373924467640518368465012204980858438160127647802572983143425507448999967241207186701518207195015015739598846687434709056793597015487555707466358473564611432637890414593517116857771284711814076853125419306285869381974622557155019992727242896503018802441210966188045211779436703341152749688824296759097963388158731237092792251164105828728858516951458791084595247591674731645830905744761534078963607725435881491831508342871545788662307953494333833994658998
追加YbでそれにCJamバイナリに戻って変換します。
ヒューリスティックについて:最初に、私が使用しているパターンがあります。9ステップごとに最初の9を繰り返します(ただし、9 * x)ステップごとにx番目のステップを繰り返します。これは、私のPythonの回答でダウンロードして使用した(ハードコードされた)ソリューションに触発されました。
パターンから逸脱した回数と、「エッジ」に到達した回数(死から1ステップ)を追跡しています。ヒューリスティック関数は、基本的にこれらの2つの数値とこれまでに実行されたステップ数の重み付き組み合わせです。
ヒューリスティックをさらに微調整して速度を向上させることができます。また、ランダムファクターを追加する方法もいくつかあります。
実際、この問題に関連する乗法関数について読んだところ、大幅な改善が得られるようです(TODO:後で実装します)。
非ゴルフとコメント:
import java.util.*;
public class Erdos implements Comparable<Erdos> {
static int n; // input (requested number of steps)
static int m, t, u; // auxiliary variables
byte[] a; // keeps each step and sum combined into 1 byte
int k = 2; // number of steps + 1 (steps are 1-based)
int edge; // number of times we got to an edge
int diff; // number of differences from the expected pattern
// start with one step
Erdos() {
a = new byte[5];
set(1, 1);
setSum(1, 1);
}
// copy constructor
Erdos(Erdos x) {
a = Arrays.copyOf(x.a, n + 1);
k = x.k;
diff = x.diff;
edge = x.edge;
}
// get the x'th step (can be -1, 0 or 1)
int get(int x) {
return (a[x] + 1) % 3 - 1;
}
// set the x'th step
void set(int x, int y) {
a[x] = (byte) (a[x] / 3 * 3 + (y + 3) % 3);
}
// get the sum of every x'th step (should be within -3..3)
int getSum(int x) {
return a[x] / 3 - 3;
}
// set the sum of every x'th step
void setSum(int x, int y) {
a[x] = (byte) (a[x] % 3 + (y + 3) * 3);
}
// try to add a step with value x (1 or -1)
Erdos grow(int x) {
if (get(k) == -x) // predetermined step doesn't match
return null;
Erdos e = new Erdos(this);
e.set(k, x);
e.setSum(e.k++, x);
for (m = 0; ++m < k;)
if (k % m < 1) { // check all divisors of k
u = e.getSum(m) + x; // updated sum
if (u == (k < 9 ? 2 : 4) * x) // use limit 2 for the first 8 steps, 4 for the rest
return null; // dead
e.setSum(m, u);
if (u == 3 * x) { // we're at an edge
e.edge++;
if (k + m <= n) { // predetermine future step - should be going back
if (e.get(k + m) == x) // conflict
return null;
e.set(k + m, -x);
}
}
}
return e;
}
public int compareTo(Erdos o) { // heuristic function
m = diff - o.diff + (edge - o.edge) / 60 + (o.k - k) / 150;
return m == 0 ? o.k - k : m;
}
public static void main(String[] a) {
n = Integer.valueOf(a[0]);
Queue<Erdos> q = new PriorityQueue<>();
q.add(new Erdos());
for (;;) {
Erdos x = q.remove(), y;
if (x.k > n) { // we made it
for (t = 0; ++t < x.k;)
System.out.print((x.get(t) + 1) / 2);
return;
}
t = x.get(x.k < 9 ? 1 : x.k % 9 == 0 ? x.k / 9 : x.k % 9); // next step based on the pattern
y = x.grow(t);
if (y != null)
q.add(y);
y = x.grow(-t);
if (y != null) {
y.diff++;
q.add(y);
}
}
}
}
n=13000と、最初の2000の指示がボーナスを獲得しますか?無意味だと思うので、おそらくあなたは何か他のものを意味しましたか?