锡兰/锡兰,49.86 40.95点
第三个版本使用Ceylon 1.2生成器和509字节的代码:
import ceylon.language{S=String,I=Integer,e=expand}S q(I n)=>n==0then"0"else(n<0then"-"+p(-n,"-")else p(n,"+"));variable Map<[I,S],S>c=map{};S p(I n,S s){S v=c[[n,s]]else(n<8then s.join([1].repeat(n)))else(let(a="+-".replace(s,""))e(e{for(x in 2..8)let(l=(n^(1.0/x)).integer){for(r in l:2)if(r>1)let(w=r^x){if(w-n<n)"("+p(r,"+")+")^("+p(x,"+")+")"+(w<n then s+p(n-w,s)else(n<w then a+p(w-n,a)else""))}}}).reduce<S>((x,y)=>x.size<y.size then x else y))else"";c=[n,s]in c then c else map{[n,s]->v,*c};return v;}
它下降到35.22点,但是我不会将其放在标题行中,因为Celyon 1.2仅在10月29日发布。我认为我无法以这种大小在Ceylon 1.1中实现此算法。)此处有更多详细信息,在这里我将介绍第二个版本。(历史上可以看到第一个版本–它仅支持正数,但确实可以容纳256个字节。)
第二版
现在是第二个版本,它支持负整数(和0),并且通常通过使用extra创建一个短一些的输出-
。(此版本实际上使用了允许的长度,第一个尝试保持在256个字节以下,而不是512个字节以下。)
String proof(Integer n) {
if (n == 0) { return "0"; }
if (n < 0) { return "-" + p(-n, "-"); }
return p(n, "+");
}
String p(Integer n, String sign) {
if (n < 9) {
return sign.join([1].repeat(n));
}
value anti = (sign == "+") then "-" else "+";
value root = ((n^0.5) + 0.5).integer;
return "(" + p(root, "+") + ")^(1+1)" +
( (root^2 < n) then sign + p(n - root^2, sign) else
((n < root^2) then anti + p(root^2 - n, anti) else ""));
}
代码的长度为487,因此以后仍有一些空间可以进行更多优化。(还有许多保留形式,包括空格和长变量名。)
得分:
Total positive: 42652
Average positive:42.652
Total negative: 43653
Average negative: 43.60939060939061
With bonus:39.24845154845155
Overall score: 40.95022577422577
一些样本输出:
27: 21: (1+1+1+1+1)^(1+1)+1+1
28: 23: (1+1+1+1+1)^(1+1)+1+1+1
29: 25: (1+1+1+1+1)^(1+1)+1+1+1+1
30: 27: (1+1+1+1+1)^(1+1)+1+1+1+1+1
31: 29: (1+1+1+1+1+1)^(1+1)-1-1-1-1-1
32: 27: (1+1+1+1+1+1)^(1+1)-1-1-1-1
33: 25: (1+1+1+1+1+1)^(1+1)-1-1-1
34: 23: (1+1+1+1+1+1)^(1+1)-1-1
-27: 22: -(1+1+1+1+1)^(1+1)-1-1
-28: 24: -(1+1+1+1+1)^(1+1)-1-1-1
-29: 26: -(1+1+1+1+1)^(1+1)-1-1-1-1
-30: 28: -(1+1+1+1+1)^(1+1)-1-1-1-1-1
-31: 30: -(1+1+1+1+1+1)^(1+1)+1+1+1+1+1
-32: 28: -(1+1+1+1+1+1)^(1+1)+1+1+1+1
-33: 26: -(1+1+1+1+1+1)^(1+1)+1+1+1
-34: 24: -(1+1+1+1+1+1)^(1+1)+1+1
993: 65: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1+1)^(1+1)+1+1+1+1+1
994: 63: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1)^(1+1)-1-1-1-1-1
995: 61: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1)^(1+1)-1-1-1-1
996: 59: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1)^(1+1)-1-1-1
997: 57: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1)^(1+1)-1-1
998: 55: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1)^(1+1)-1
999: 53: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1)^(1+1)
1000: 55: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1)^(1+1)+1
-993: 66: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1+1)^(1+1)-1-1-1-1-1
-994: 64: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1)^(1+1)+1+1+1+1+1
-995: 62: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1)^(1+1)+1+1+1+1
-996: 60: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1)^(1+1)+1+1+1
-997: 58: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1)^(1+1)+1+1
-998: 56: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1)^(1+1)+1
-999: 54: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1)^(1+1)
-1000: 56: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1)^(1+1)-1
1: 1: 1
2: 3: 1+1
3: 5: 1+1+1
4: 7: 1+1+1+1
5: 9: 1+1+1+1+1
6: 11: 1+1+1+1+1+1
7: 13: 1+1+1+1+1+1+1
8: 15: 1+1+1+1+1+1+1+1
9: 13: (1+1+1)^(1+1)
10: 15: (1+1+1)^(1+1)+1
0: 1: 0
-1: 2: -1
-2: 4: -1-1
-3: 6: -1-1-1
-4: 8: -1-1-1-1
-5: 10: -1-1-1-1-1
-6: 12: -1-1-1-1-1-1
-7: 14: -1-1-1-1-1-1-1
-8: 16: -1-1-1-1-1-1-1-1
-9: 14: -(1+1+1)^(1+1)
-10: 16: -(1+1+1)^(1+1)-1
如您所见,负数始终-
比对应的正数长1个字节(前导)。
基本思路与之前的程序相同:在目标编号附近找到一个正方形,并递归地表示其根和余数。但是现在我们允许平方也比目标数大一些,这会使余数变为负数。(+0.5
可以将其更改为其他常数来调整算法,但是似乎我已经达到了最佳值– 0.4和0.6都给出较差的结果。)
为了使负值sign
变为负值(否则与正值具有相同的结构,我们将运算符传递给递归函数p
- "+"
或"-"
。在平凡的情况下(即n <9),我们也可以将其用于联接器)如果是正数则表示余数,如果是负数则使用相反的符号。
该proof
函数处理初始符号(特殊情况为0),p
并通过递归进行实际工作。
第三版,适用于锡兰1.2
import ceylon.language { S=String, I=Integer,e=expand }
// output a base-proof Ceylon expression for an integer
// (i.e. using only 0 and 1 as digits).
//
// Question: http://codegolf.stackexchange.com/q/58084/2338
// My Answer: http://codegolf.stackexchange.com/a/58122/2338
//
// The goal is to produce an expression as short as possible, with
// the code staying under 512 bytes in length.
//
// This approach is to represent a positive integer as a square
// of a positive integer plus some remainder (where the remainder
// can be negative), and for negative integers replace the + on the
// outer level by -.
S q(I n) =>
n == 0 then "0"
else (n < 0 then "-" + p(-n, "-")
else p(n, "+"));
// cache for values of p
variable Map<[I, S],S> c = map { };
// Transforms a positive number into a base-proof term, using
// the given sign for the summation on the outer level.
S p(I n, S s) {
S v =
// look into the cache
c[[n, s]] else (
// hard-code small numbers
n < 8 then s.join([1].repeat(n)))
else
// do the complicated stuff
(let (a = "+-".replace(s,""))
e(e {
for (x in 2..8) // try these exponents
let (l = (n ^ (1.0 / x)).integer) // \[ sqrt[exp]{n} \] in LaTeX
{ for (r in l:2) // lowerRoot, lowerRoot + 1
if (r > 1)
let (w = r ^ x)
{ if (w-n < n) // avoid recursion to larger or same number
// format the string as r^x + (n-w)
"(" + p(r, "+") + ")^(" + p(x, "+") + ")" +
(w < n then s + p(n - w, s)
else (n < w then a + p(w - n, a)
else ""))
} } })
// and now find the shortest formatted string
.reduce<S>((x, y) => x.size < y.size then x else y))
// this should never happen, but we can't tell the compiler
// that at least some of the iterables are non-empty due to the if clause.
else "";
// this builds a new cache in each step – quite wasteful,
// as this also happens when the value was found in the cache,
// but we don't have more characters remaining.
//// c = map { [n, s] -> v, *c };
///better way:
c = [n,s] in c then c else map{[n,s]->v, *c};
return v;
}
高尔夫版本(即注释和空格已删除)张贴在顶部,恰好是509字节的代码。
这使用了与第二个版本相同的基本原理,但是它不仅使用正方形,还尝试使用更高的数字幂(尝试将指数从2扩展到8),并使用最短的结果。它还缓存结果,否则,对于具有许多递归调用的较大数量的数据,这将是令人无法接受的缓慢。
得分:
Total positive: 36622
Average positive: 36.622
Total negative: 37623
Average negative: 37.58541458541458
With bonus:33.826873126873124
Overall score: 35.22443656343656
中间最大的缩进构造是三个嵌套的可迭代理解,内部两个是let表达式。然后使用expand函数将它们取消嵌套两次,然后该reduce
函数查找这些字符串中最短的字符串。
我已经提出了一项功能要求,以便能够一次完成该任务。
在理解内,我们从根r
,指数x
和余数(n-w
或w-n
)构建一个字符串。
的let
表达和map
功能在锡兰1.2是新的。map
可能已被替换为HashMap
(这将需要更多字符进行导入,尽管可能会更快,因为我不会为每个新条目构建新的地图)。let
像这样的表达式let (w = r ^ x)
可以通过使用if
类似的子句来替换if(exists w = true then r ^ x)
(然后我也不需要两个expand
调用),但是这仍然会更长一些,无法容纳511个允许的字节。
在这里,与上面选择的输出相对应的样本输出,除了非常小的数字之外,所有其他输出均较短:
27: 15: (1+1+1)^(1+1+1)
28: 17: (1+1+1)^(1+1+1)+1
29: 19: (1+1+1)^(1+1+1)+1+1
30: 21: (1+1)^(1+1+1+1+1)-1-1
31: 19: (1+1)^(1+1+1+1+1)-1
32: 17: (1+1)^(1+1+1+1+1)
33: 19: (1+1)^(1+1+1+1+1)+1
34: 21: (1+1)^(1+1+1+1+1)+1+1
-27: 16: -(1+1+1)^(1+1+1)
-28: 18: -(1+1+1)^(1+1+1)-1
-29: 20: -(1+1+1)^(1+1+1)-1-1
-30: 22: -(1+1)^(1+1+1+1+1)+1+1
-31: 20: -(1+1)^(1+1+1+1+1)+1
-32: 18: -(1+1)^(1+1+1+1+1)
-33: 20: -(1+1)^(1+1+1+1+1)-1
-34: 22: -(1+1)^(1+1+1+1+1)-1-1
993: 39: ((1+1+1)^(1+1)+1)^(1+1+1)-1-1-1-1-1-1-1
994: 37: ((1+1+1)^(1+1)+1)^(1+1+1)-1-1-1-1-1-1
995: 35: ((1+1+1)^(1+1)+1)^(1+1+1)-1-1-1-1-1
996: 33: ((1+1+1)^(1+1)+1)^(1+1+1)-1-1-1-1
997: 31: ((1+1+1)^(1+1)+1)^(1+1+1)-1-1-1
998: 29: ((1+1+1)^(1+1)+1)^(1+1+1)-1-1
999: 27: ((1+1+1)^(1+1)+1)^(1+1+1)-1
1000: 25: ((1+1+1)^(1+1)+1)^(1+1+1)
-993: 40: -((1+1+1)^(1+1)+1)^(1+1+1)+1+1+1+1+1+1+1
-994: 38: -((1+1+1)^(1+1)+1)^(1+1+1)+1+1+1+1+1+1
-995: 36: -((1+1+1)^(1+1)+1)^(1+1+1)+1+1+1+1+1
-996: 34: -((1+1+1)^(1+1)+1)^(1+1+1)+1+1+1+1
-997: 32: -((1+1+1)^(1+1)+1)^(1+1+1)+1+1+1
-998: 30: -((1+1+1)^(1+1)+1)^(1+1+1)+1+1
-999: 28: -((1+1+1)^(1+1)+1)^(1+1+1)+1
-1000: 26: -((1+1+1)^(1+1)+1)^(1+1+1)
1: 1: 1
2: 3: 1+1
3: 5: 1+1+1
4: 7: 1+1+1+1
5: 9: 1+1+1+1+1
6: 11: 1+1+1+1+1+1
7: 13: 1+1+1+1+1+1+1
8: 13: (1+1)^(1+1+1)
9: 13: (1+1+1)^(1+1)
10: 15: (1+1+1)^(1+1)+1
0: 1: 0
-1: 2: -1
-2: 4: -1-1
-3: 6: -1-1-1
-4: 8: -1-1-1-1
-5: 10: -1-1-1-1-1
-6: 12: -1-1-1-1-1-1
-7: 14: -1-1-1-1-1-1-1
-8: 14: -(1+1)^(1+1+1)
-9: 14: -(1+1+1)^(1+1)
-10: 16: -(1+1+1)^(1+1)-1
例如,现在我们有1000 =(3 ^ 2 + 1)^ 3,而不是1000 =(6 ^ 2-4)^ 2-5 ^ 2 + 1。
0
还是1
默认变量?