バイナリ文字列とそのペアの間の全単射


8

入力:「0」と「1」の1つまたは2つの文字列。2つある場合は、スペースで区切られます。すべての文字列の長さが少なくとも1です。

出力:1つの文字列が入力された場合、2つが出力されます。2が入力された場合、1が出力されます。出力文字列は何でもかまいませんが、入力Aでプログラムを実行するとBが得られ、Bで実行するとAが得られます(入力111 11が与える00000場合、入力00000は与える必要があります111 11)。

つまり、プログラムをそれ自体にパイプすると、入力したものは何でも取得できるはずです。プログラムがfooと呼ばれる場合、次のようにテストできます。

>echo 101 101|foo|foo
101 101

ブルートフォーステクニックの使用を防ぐには、コードを10秒間で1000桁の文字列で実行できる必要があります。これに対する私のpythonソリューションは、10,000桁の文字列で1秒未満なので、これは問題になりません。

最短のコードが勝ちます。

回答:


3

Python、183

バイジェクションはディスクにキャッシュされます。

x=raw_input()
try:d=eval(open('d').read())
except:d={'':'','1 ':'1 '}
t='1 '*not' 'in x
if x not in d:
 while t in d:t+=`(id(t)/9)%2`
 d[t]=x;d[x]=t
 open(*'dw').write(`d`)
print d[x]

編集:おっと、これは最初のスマートな答えではないようです。鉱山は実行間で一貫しています!


バイトに置き換えif x not in d:if(x in d)-1:保存できます。
Jonathan Frech

2

Python、326

s=lambda i,l:bin(i)[2:].zfill(l)
f=lambda n:2**n*(n-3)+4
g=lambda n:2**n-2
i=raw_input()
if' 'in i:
 a,b=i.split();n=len(a+b);r=f(n)+int(a+b,2)*(n-1)+len(a)-1;l=1
 while g(l+1)<=r:l+=1
 print s(r-g(l),l)
else:
 n=len(i);r=g(n)+int(i,2);l=2
 while f(l+1)<=r:l+=1
 r-=f(l);p=r%(l-1)+1;w=s(r/(l-1),l);print w[:p],w[p:]

入力/出力の例:

     input | output
-----------+-----------
         0 | 0 0
       0 0 | 0
     10 10 | 10101
     10101 | 10 10
0000000000 | 101 0100
  101 0100 | 0000000000

2

Perl 5、197文字

sub n{'0'x$_[0].sprintf'%b',$_[1]}sub N{/0*(?=.)/;length$&,oct"0b$'"}$_=<>;print/ /?n map{($a,$b)=N;($a+$b)*($a+$b+1)/2+$b}split:"@{[map{$w=int((sqrt(8*$_+1)-1)/2);$y=$_-($w*$w+$w)/2;n$w-$y,$y}N]}"

いくつかの改行あり:

sub n{'0'x$_[0].sprintf'%b',$_[1]}
sub N{/0*(?=.)/;length$&,oct"0b$'"}
$_=<>;print/ /?n map{
  ($a,$b)=N;($a+$b)*($a+$b+1)/2+$b
}split:"@{[map{
  $w=int((sqrt(8*$_+1)-1)/2);$y=$_-($w*$w+$w)/2;n$w-$y,$y
}N]}"

このプログラムは、2つの全単射を組み合わせて動作します。

  • 自然数のペアは、一方を2を底とする数値に変換し、もう一方を無関係な先行ゼロに変換することにより、バイナリ文字列にマッピングできます。nはこの関数でNあり、その逆です(パラメーターとしてをN使用する場合を除く$_)。

  • Cantorのペアリング関数を使用して、自然数のペアを単一の自然数にマップできます。最初mapののブロックはこの関数で、2番目のブロックはその逆です。

したがって、2つのバイナリ文字列は4つの数値に分割され、2つの数値に結合されて、1つのバイナリ文字列に結合されます(またはその逆)。

最大8シンボルまでの文字列を使用して、各タイプの100個のランダム入力でテストされています。私はこれを少し短くする方法をたくさん見つけてきましたが、それをやめて投稿します。さらに最適化する余地がある場合、それはおそらく算術式にあります。


入力1111111111111111111111111111111111111111111111111111111111111111(64 1秒)がクラッシュすると思われ、一対の入力0と50 1秒と同じ結果が得られる0と51 1Sを、その出力64個の両方1S。私は一流の数のオーバーフローのいくつかの種類があると思う0ソリューションは、出力を取得するかもしれないのでsが、N入力のカントールのペアから値をN値、とnのペアリングからの値n(逆のためにその逆または副)の値。私はperl noobなので、何か間違ったことをしたかもしれません。
cardboard_box

はい、このプログラムは、Perlが整数として処理するには1を含む部分が大きすぎるバイナリ文字列に対しては機能しません。アルゴリズムの優雅さと引き換えに、それは妥当な実装制限であると感じました。原則として、すべての数値演算はbigint演算に置き換えることができます。
Kevin Reid

1

Perl、56文字

-pコマンドラインスイッチに+1文字を追加

$s.=1;$h{$h{$_}||=(split>1?$s:"$s $s").$/}=$_;$_=$h{$_}

多分私は十分に明確ではなかった。私はあなたのプログラムに何らかの入力を取り、いくつかの出力を印刷してから終了させたいと思っています。次に、出力を入力としてプログラムを再度実行すると、最初に入力した内容が返されます。
cardboard_box

@cardboard_boxマッピングは複数の実行間で持続する必要がありますか?あなたは本当にそれを問題の説明に追加する必要があります
ardnew '11

0

Python、394

これはもっとゴルフできると確信していますが、このモノリスはCantorペアリング関数とその逆を使用しています。

import math
s=lambda n:n*(n+1)/2
p=lambda a:'0'*a[0]+bin(a[1])[2:]
q=lambda t:t.index('1')
B=raw_input().split()
def f(x,y):r=x+y+1;return s(r)-[y,x][r%2]-1
def g(z):r=int(math.ceil((2*(z+1)+1/4.)**(1/2.)-1/2.))-1;d=s(r+1)-z-1;return [(d,r-d),(r-d,d)][r%2]
if len(B)<2:a=[g(q(B[0])),g(int(B[0],2))];print p(a[0])+' '+p(a[1])
else:print p([f(q(B[0]),int(B[0],2)),f(q(B[1]),int(B[1],2))])

説明

バイナリ文字列と自然数のペアの間には自然な関連があります。画像の最初の数は先行ゼロの数であり、2番目は2進数の整数値です。私たちが知っていること:

S ~ N^2

カンター全単射と

N ~ N^2

したがって:

S ~ N^2 ~ N^4 ~ S^2

S ~ S^2

Sはすべてのバイナリ文字列のセットです。このソリューションは、SとS ^ 2の間の全単射を実装します。


これがすべて0の入力で失敗することに気付いたばかりです。明日修正します。今はpythonに飽きています-_-
scleaver
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.