找回密码


12

普通的N位数字密码锁由N个旋转盘组成。每个光盘上都有按顺序刻印的数字0-9,您需要将它们转换为正确的密码才能打开它。显然,如果您不知道密码,则在解锁之前最多需要尝试10 N次。那没意思。

密码锁

因此,让我们考虑一下组合锁的一种变体,将其命名为距离公开锁。

在每次尝试不打开距离显示锁的尝试中,它都会响应最小数量的动作以解锁。

一个运动是通过一个位置定义为一个旋转,例如,它需要从1个运动890899,并且从9个运动137952

挑战

给定具有密码未知的距离揭示锁,请尝试以最少的尝试次数(而不是移动)打开锁,同时防止程序过长。

规则和计分

  • 您应该编写一个完整的程序,该程序将从stdin输入并将其输出到stdout。该程序应执行以下输入/输出:
Start
    Input an integer N (number of digits) from stdin
    Do
        Output a line containing decimal string of length N (your attempt) to stdout
        Input an integer K (response of the lock) from stdin
    While K not equal 0
End
  • 您的程序最多可以处理N = 200,并且在任何输入上都应运行少于5秒。

  • 输出中的前导零不应该被忽略。

  • 每个长度有5个测试数据,因此测试数据的总数为1000。该测试数据是随机生成的。

  • 最终分数将是(所有测试数据中的猜测总数)* ln(以字节为单位的代码长度+ 50)。最低分获胜。(ln是自然对数)

  • 我会为您评分该程序。如果您想知道我将如何给您的程序打分,或者想自己给它打分,请查看此帖子以前的修改

  • 该挑战赛将于世界标准时间2017/12/07 14:00结束。然后,我将发布解决方案。

运行示例

以行开头的行>代表输入,其他行代表程序输出。

您可以记住一个密码,然后与您的程序进行交互以对其进行测试。

> 3   # 3-digit lock. The hidden password is 746
000   # 1st guess (by program)
> 11  # response to the 1st guess
555   # 2nd guess
> 4   # ...
755
> 2
735
> 2
744
> 2
746   # finally the correct answer! The program attempts 6 times.
> 0   # this is not necessary

样例程序

编辑:也许上面的输入/输出格式不清楚。这是Python中的示例程序。

Python,369个字节,尝试总次数= 1005973,得分= 6073935

import sys

N = int(input()) # get the lock size

ans = ''
for i in range(N): # for each digit
    lst = []
    for j in range(10): # try all numbers
        print('0' * i + str(j) + '0' * (N - i - 1)) # make a guess
        result = int(input()) # receive the response
        lst.append(result)
    ans += str(lst.index(min(lst)))
print(ans) # output the final answer

感谢Jonah简化了挑战。

Answers:


3

C,388个 374 368个字节,总尝试次数= 162751,得分= 982280

char s[999];i;G;H;t;n;h;e;R(x){scanf("%d",x);}W(i,x,a){printf((i-n?0:4)+"%0*d%0*d\n",i,x,n-i,0);R(a);}S(k,i){if(!(t=e=k>4?s[i]=48:k<1?s[i]=53:!G?H=k,G=i:0)){for(;t++<n;)putchar(48|t==i|t==G);puts("");R(&t);t==h?W(G,e=1,&t):0;s[G]=t>h?53+H:53-H,s[i]=t>h^e?53+k:53-k;G=0;}}main(){R(&n);for(W(n,0,&h);i++<n;S(t-h+5>>1,i))W(i,5,&t);s[G]=53+H,puts(s+1),s[G]=53-H,puts(s+1);}

欢迎来到PPCG!您的得分很好162751*ln(388+50)=989887
Colera Su

3

C#(.NET Core),617字节,总尝试次数= 182255,得分= 1185166

using System;namespace p{class C{static void Main(){var l=Console.ReadLine();int L=int.Parse(l);var g=new int[L];var p=n(g);for(int i=0;i<L;i++){g[i]=5;var d=n(g);var f=d-p;var s=f;switch(s){case 5:g[i]=0;d-=5;break;case-5:break;case 3:g[i]=1;d=n(g);f=d-p;if(f>0){g[i]=9;d-=2;}break;case 1:g[i]=2;d=n(g);f=d-p;if(f>0){g[i]=8;d-=4;}break;case-1:g[i]=3;d=n(g);f=d-p;if(f>0){g[i]=7;d-=4;}break;case-3:g[i]=4;d=n(g);f=d-p;if(f>-3){g[i]=6;d-=2;}break;}p=d;}n(g);}static int n(int[] g){foreach(var i in g){Console.Write(i);}Console.WriteLine();var s=Console.ReadLine();var d=int.Parse(s);if(d<1) Environment.Exit(0);return d;}}}

希望这种格式的C#对您有用。它采用完整程序的形式,因此应该有一种编译为可执行文件的方法。让我知道是否有什么我可以做的使它变得更容易。字节是计分的一部分,即使已删除Code Golf标签,所以我的正式呈文也删除了所有不需要的空格和有用的名称。我在下面的解释将使用非高尔夫代码的片段:

说明

该程序仅使用一个辅助方法:

static int newGuess(IEnumerable<int> guess)
        {
            foreach (var item in guess)
            {
                Console.Write(item);
            }
            Console.WriteLine();
            var distanceString = Console.ReadLine();
            var distance = int.Parse(distanceString);
            if (distance < 1) System.Environment.Exit(0);
            return distance;
        }

这会将猜测写入stdout,然后读取与stdin的距离。如果猜测是确切的组合,它也会立即结束程序。我叫很多。接下来的初始设置:

var lengthString = Console.ReadLine();
int length = int.Parse(l);
var guess = new int[length];
var prevDistance = newGuess(guess);

这将获得组合的长度,然后开始用全0进行猜测。然后,循环遍历每个数字for

guess[i] = 5;
var distance = newGuess(guess);
var difference = distance - prevDistance;
var switchVar = difference;
switch (switchVar)

对于每个数字,它猜测为5,然后根据自上一个猜测(该数字为0)以来的距离变化,决定下一步。

case 5:
    guess[i] = 0;
    distance -= 5;
    break;

如果距离增加5,则该距离为0正确。将该数字调整回0。手动更改记录的距离可以避免额外的猜测。

case -5:
    break;

如果距离减少5,则5是正确的数字,我们将立即移至下一个数字。

之后,事情变得很棘手。对于我的初步猜测,使用50意味着其余的差异可能性分别3, 1, -1, -3具有2种可能性,需要另外进行1种猜测才能区分。这些情况均采用类似的形式

case 3:
    guess[i] = 1;
    distance = newGuess(guess);
    difference = distance - prevDistance;
    if (difference > 0)
    {
        guess[i] = 9;
        distance -= 2;
    }

一些数字发生了变化,但实际上我们尝试了两种可能性之一,并检查该变化对于该数字是否正确。如果不是,则其他数字正确,因此我们设置该数字,然后手动调整差异。

这种方法意味着我们最多应要求对初始0进行1个猜测,每位数2个猜测,然后对1个最终猜测进行确认以确保最后一位不会丢失。

虽然它可能有问题,但据我手动检查,它仍然可以工作,但不能保证。 感谢Colera Su找到并压缩了错误


我测试了它,当答案为时,它不起作用37。输出为:(00, 50, 30, 75, 75是,两个75s)。
Colera Su

替换<>in ifin switch似乎可以修复该错误。如果那是您想要的,您的分数是182255*ln(617+50)=1185166
Colera Su

@ColeraSu确实!缩短代码时,我肯定在查找/替换上犯了一个错误。我已经修正了高尔夫代码(详细版本具有正确的比较)。
卡米尔·德拉科里

2

Python 2和3:175个字节,总尝试次数= 1005972,得分= 5448445

该程序每个组合进行ceil(log(n))* 10次尝试,或者每个数字进行10次尝试(因此,333进行30次尝试)。

N=int(input());o=0
def c(a):
 print("0"*(N-len(str(a)))+str(a))
 return int(input())
for j in range(N):m={c(i):i for i in reversed(range(0,10**(j+1),10**j))};o+=m[min(m)]
c(o)

非常感谢Colera Su为我提供输入/输出功能的帮助。

挑战的Python版本(由OP修改)。

我在Python内部编写了一个锁代码版本。如果您想用Python解决这个问题,可以继续使用。以下内容可在Python 2和3中工作。将锁实现为可以测试的类非常有意义,我决定创建一个生成器函数来猜测输入。

import sys

class Lock:
    def __init__(self, number):
        self.lock = str(number)
    def l(self): #lengthOfNumber
        return len(self.lock)
    def c(self, guess): #check a guess
        guess = str(guess)
        guess = "0" * (len(self.lock) - len(guess)) + guess
        difference = 0
        for i in range(len(self.lock)):
            d1 = abs(int(self.lock[i]) - int(guess[i]))
            d2 = 10 - d1
            difference += d1 if d1 < d2 else d2
        return difference

def masterLock():
    testdata = ["000","555","755","735","744","746"]
    for answer in testdata:
        yield Lock(answer)

class LockIO:
    def __init__(self):
        self.lock = int(input())
    def l(self):
        return self.lock
    def c(self, guess):
        guess = str(guess)
        guess = "0" * (self.lock - len(guess)) + guess
        print(guess)
        sys.stdout.flush()
        return int(input())

for l in masterLock():
    # Write your code here that tries to guess it
    #   When you're done testing you can unindent your code,
    #   replace "for l in masterLock():" with "l = LockIO()"
    #   and submit the code.
    # 
    # Examples:
    #  l.l()      # returns the length of the lock
    #  l.c("952") # returns the distance to the lock
    #  l.c(952)   #  number also works
    pass

首先,很抱歉我写的LockIO课错了。我已发送了一个编辑请求。第二,我认为您误解了评分标准。分数是由生成器生成的测试数据计算出来的,而不是示例(我执行了您的程序,总数为1005972)。自然对数也丢失了。第三,我已经指定您需要提供完整的程序,因此您也应该LockIO在字节数中包括该部分。此外,您需要输出最终结果,该结果也计入分数。
Colera Su

@ColeraSu这里的“ Class LockIO”有什么关系?另外,第二段Python代码用于什么?
user202729

@ user202729 LockmasterLock只是为了方便测试。LockIO是您实际需要提交的内容,因为它使用了所需的I / O格式。
Colera Su

@nfnneil我在主帖子中添加了一个示例程序。我还发送了一个编辑请求供您参考。
Colera Su

@ColeraSu当我入睡时,我意识到了你的意思,谢谢男人。这是一个很好的挑战。
尼尔

2

R277个字节(分数= 1175356) 258个字节,总尝试次数= 202999,得分= 1163205

f=file("stdin","r")
w=function(b=1,A=X){cat(A,"\n",sep="");if(b){b=scan(f,n=1)};b}
M=0:9
s1=c(-5,-3,-1,1,3,5,3,1,-1,-3)
s2=s1+rep(c(1,-1),,,5)
L=w(1,"")
X=S=rep(0,L)
v0=w()
for(i in 1:L){X[i]=5
v1=v0-w()
X[i]=4
v2=v0-w()
S[i]=M[s1==v1&s2==v2]
X=0*S}
b=w(0,S)

在线尝试!

根据OP的要求,Stdin-stdout版本没有样板。感谢Colera Su修复了最初的错误。该版本比注释中的版本略短。


在TIO提交下方的此处可在TIO中运行一批测试

R,189字节

M=0:9
s1=c(-5,-3,-1,1,3,5,3,1,-1,-3)
s2=c(-4,-2,0,2,4,4,2,0,-2,-4)
f=function(L){S=rep(0,L)
v0=v(S)
X=S
for(i in c(1:L)){X[i]=5
v1=v0-v(X)
X[i]=4
v2=v0-v(X)
S[i]=M[s1==v1&s2==v2]
X[i]=0}
S}

在线尝试!

让我们考虑零向量作为初始猜测。我们将当前猜测和解之间的距离称为V。对于每个位置,将0替换为5并替换为4时,只需要检查V的变化即可。实际上,矢量s1中列出了将0替换为5之间的差异。我的向量s2中列出了将0更改为4之间的差异。如您所见,这两个向量唯一地映射了解决方案的数字。

因此,测试的总数为3 * L 2 * L + 1,其中L是代码的长度:对所有零的初始检查,然后对每个数字进行两次检查,一次对5,一次对4。

Kamil Drakari的建议启发了从3到2的改进。

TIO提交的其余部分是R的样板。TIO提交显示了运行时间和L = 1 ... 200的1000次运行的操作总数,每个L值重复5次。


Error in scan(n = 1) : scan() expected 'a real', got 'S=rep(0,L)'在执行时得到。
Colera Su

1
看来scan(file=file("stdin"),n=1)可行。该程序(与您的程序相同,只是更正了I / O)的得分为202999*ln(277+50)=1175356
Colera Su

@ColeraSu,我可能错过了一些东西,但是我认为202999*ln(258+50) != 202999*ln(277+50)
NofP

似乎@ user202729输入了错误。固定。
Colera Su
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.