整数からビット文字列へのコンパクトなコーディング


8

それぞれのx最大値mがわかっているステートレスデコーダーを元の整数にデコードできるように、正の整数をビットにコンパクトにコード化したいx。ハフマン符号化の場合のように、符号化の連結を一意に復号化することが可能でなければならない。
[上記の紹介は残りの動機付けとなりますが、正式な定義の一部ではありません]

表記:負でない整数の場合i、バイナリでn(i)表すのiに必要なビット数とします。それは次のkような負でない最小の整数ですi>>k == 0

  i :   0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18  ..
n(i):   0   1   2   2   3   3   3   3   4   4   4   4   4   4   4   4   5   5   5   ..

およびに対してF(x,m)定義された関数が必要です。出力には ' 'または ' 'の文字列があり、次のプロパティがあります。0<xx<=m01

  1. F(x,m)2*n(x)またはの2*n(m)-1どちらか短い方の長さです。
  2. その場合x<y:
    • F(x,m)より長くないF(y,m);
    • F(x,m)そしてF(y,m)、長さのある位置で異なりますF(x,m)。
    • そのような最初の位置に0インがありF(x,m)ます。
  3. 特定のmプロパティ1と2が最大でF(x,m)すべての正に対して一意に定義されていない場合、長さが一致しない最小のものに対して、他の受け入れ可能なエンコーディングよりも長いエンコーディングを拒否します。xmF(x,m)x

注:上記の、暗黙的には0<x、0<y、0<m、x<=m、およびy<=m、その結果F(x,m)とF(y,m)定義されます。

上記の制約と最大9桁の10進数xをm満たしF(x,m)、上記の規則と一致する出力を行うことが最短のプログラムに求められます。次のCフレームワーク(または他の言語では同等のもの)はカウントされません。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define C(c) putchar((c)?'1':'0') // output '0' or '1'
#define S(s) fputs((s),stdout)    // output a string
typedef unsigned long t;          // at least 32 bits
void F(t x,t m);                  // prototype for F
int main(int argc,char *argv[]){
 if(argc==3)F((t)atol(argv[1]),(t)atol(argv[2]));
 return 0;}
void F(t x,t m) {   // counting starts on next line
}                   // counting ends before this line

コメント:プロパティ1は、エンコードされた長さを積極的に制限します。プロパティ2は、明確なデコードが可能であることを形式化し、エンコードを正規化します。私は(証明なしで)これはFwhen の出力m+1が2の累乗を一意に定義するのFに十分であり、プロパティ3はother を一意に定義するのに十分であることを主張しますm。

ここに部分的な表があります(手作り、投稿された最初のバージョンはエラーで謎でした、申し訳ありません):

  x     :   1       2       3       4       5       6       7       8       9       10      11      12      13      14      15
F(x,1)  : empty
F(x,2)  :   0       1
F(x,3)  :   0       10      11
F(x,4)  :   0       10      110     111
F(x,5)  :   0       10      110     1110    1111
F(x,6)  :   0       100     101     110     1110    1111
F(x,7)  :   0       100     101     1100    1101    1110    1111
F(x,8)  :   0       100     101     110     11100   11101   11110   11111

F(x,15) :   0       100     101     11000   11001   11010   11011   111000  111001  111010  111011  111100  111101  111110  111111

「コンパクトコーディング?」これは、整数の正規の2進数表現よりもどのようにコンパクトですか?:)
— マーティンエンダー14

@ m.buettner:基数2の正規表現の問題は、3、7、7、3、1、15、およびその他の多くのものがすべてとしてエンコードされ11111、デコードが不可能になることです。提案されたコーディングを使用すると、いくつかの出力の連結を一意にデコードできます(m動的に変化する最大値を含む)。私はそれを明確にしようとしました。
— fgrieu 14

1
私はあなたのテーブルに同意しません。F(x、5)の場合、0,100,101,110,111になります。ただし、エンコーディング0、10、110、1110、1111は(1)と(2)を満たし、10は100より短いため、F(x、5)のエンコーディングは拒否されます。
— nneonneo 14

1
ああ、でもF(x、8)の場合、テーブルはまだ間違っています。0,100,101,110,11100,11101,11110,11111はF(4,8)に適しています(110対1100)。
— nneonneo

1
いいえ。F(7,8)は6桁未満でなければならないため、これは不正です。
— nneonneo 14

回答:


1

Python 3、163バイト

n=int.bit_length
R=range
def F(x,m,c=0):
 for i in R(x):L=2*n(m)-2;D=1<<L;r=n(D-c-sum(D>>min(2*n(x+1)-1,L)for x in R(i+1,m)))-1;v=c;c+=1<<r
 return bin(v)[2:L+2-r]

c=0パラメータは無視してください。これはゴルフのトリックです。

これは、残りの数値がまだ表現可能であるという条件に従って、各数値に対して可能な限り短い表現を貪欲に選択します。したがって、構造上、目的の特性を正確に満たします。結果として、実際にこのコードを変更して異なるコーディングルールのセットをサポートすることはそれほど難しくありません。

たとえば、次の出力はm=15次のとおりです。

m\x |   1       2       3       4       5       6       7       8       9       10      11      12      13      14      15
----+----------------------------------------------------------------------------------------------------------------------------
1   |   
2   |   0       1
3   |   0       10      11
4   |   0       10      110     111
5   |   0       10      110     1110    1111
6   |   0       100     101     110     1110    1111
7   |   0       100     101     1100    1101    1110    1111
8   |   0       100     101     110     11100   11101   11110   11111
9   |   0       100     101     110     11100   11101   11110   111110  111111
10  |   0       100     101     1100    1101    11100   11101   11110   111110  111111
11  |   0       100     101     1100    1101    11100   11101   111100  111101  111110  111111
12  |   0       100     101     1100    11010   11011   11100   11101   111100  111101  111110  111111
13  |   0       100     101     1100    11010   11011   11100   111010  111011  111100  111101  111110  111111
14  |   0       100     101     11000   11001   11010   11011   11100   111010  111011  111100  111101  111110  111111
15  |   0       100     101     11000   11001   11010   11011   111000  111001  111010  111011  111100  111101  111110  111111

2

Python、171

def F(x,m):
 a=0;b=[9]
 while len(b)<m:
    if 4**len(bin(len(b)))*2>64*a<4**len(bin(m)):
     if(a&a+1)**a:b+=[a];a+=1
     else:a*=2
    else:a=b.pop()*2
 return bin((b+[a])[x])[2:]

4つのスペースで始まるように見える行は、実際にはタブで始まることに注意してください。

bitpwnerのテストスクリプトを使用したテスト:

         1        2        3        4        5        6        7        8        9        10       11       12       13       14       15      
F(x,1)   0       
F(x,2)   0        1       
F(x,3)   0        10       11      
F(x,4)   0        10       110      111     
F(x,5)   0        10       110      1110     1111    
F(x,6)   0        100      101      110      1110     1111    
F(x,7)   0        100      101      1100     1101     1110     1111    
F(x,8)   0        100      101      110      11100    11101    11110    11111   
F(x,9)   0        100      101      110      11100    11101    11110    111110   111111  
F(x,10)  0        100      101      1100     1101     11100    11101    11110    111110   111111  
F(x,11)  0        100      101      1100     1101     11100    11101    111100   111101   111110   111111  
F(x,12)  0        100      101      1100     11010    11011    11100    11101    111100   111101   111110   111111  
F(x,13)  0        100      101      1100     11010    11011    11100    111010   111011   111100   111101   111110   111111  
F(x,14)  0        100      101      11000    11001    11010    11011    11100    111010   111011   111100   111101   111110   111111  
F(x,15)  0        100      101      11000    11001    11010    11011    111000   111001   111010   111011   111100   111101   111110   111111  

説明:

これはすべて、コードの2つの連続する要素F(x、m)とF(x + 1、m)の間で、常に2進数に1を追加し、次に2倍することを数回観察したことに基づいています。これらの手順に従っている場合、それは有効なコードです。残りは単純にテストして、十分に短いことを確認します。

ゴルフ:175-> 171:2 **(2 * ...を4 **に変更


Nit:F(1,1)は空の文字列でなければなりません。
— nneonneo 14

1

パイソン-370

ハフマンツリーを作成し、ルールに合わせてバランスを調整してから、ツリーをウォークスルーして最終的な値を取得します。

def w(n,m,c,p=""):
    try:[w(n[y],m,c,p+`y`)for y in 1,0]
    except:c[n[0]]=p
d=lambda x:len(x)>1and 1+d(x[1])
v=lambda x,y:v(x[1],y-1)if y else x
def F(x,m):
    r=[m];i=j=0
    for y in range(1,m):r=[[m-y],r]
    while d(r)>len(bin(m))*2-6-(m==8):g=v(r,i);g[1],g[1][0]=g[1][1],[g[1][0],g[1][1][0]];i,j=[[i+1+(d(g)%2<1&(1<i<5)&(m%7<1)),j],[j+1]*2][d(g)<5]
    c={};w(r,m,c);return c[x]

緊急パターンに基づくより簡潔なソリューションについては、isaacgの回答をご覧ください。
これは、まったく異なるアプローチが問題を解決する方法の良い例です。

テスト:

chars = 8
maxM = 15
print " "*chars,
for m in range(1,maxM+1):
    p = `m`
    print p+" "*(chars-len(p)),
print
for m in range(1,maxM+1):
    p = "F(x,"+`m`+")"
    print p+" "*(chars-len(p)),
    for x in range(1,maxM+1):
        try:
            q = `F(x,m)`[1:-1]
            print q+" "*(chars-len(q)),
        except:
            print
            break

結果:

         1        2        3        4        5        6        7        8        9        10       11       12       13       14       15      
F(x,1)           
F(x,2)   0        1       
F(x,3)   0        10       11      
F(x,4)   0        10       110      111     
F(x,5)   0        10       110      1110     1111    
F(x,6)   0        100      101      110      1110     1111    
F(x,7)   0        100      101      1100     1101     1110     1111    
F(x,8)   0        100      101      1100     1101     1110     11110    11111   
F(x,9)   0        100      101      1100     1101     1110     11110    111110   111111  
F(x,10)  0        100      101      1100     1101     11100    11101    11110    111110   111111  
F(x,11)  0        100      101      1100     1101     11100    11101    111100   111101   111110   111111  
F(x,12)  0        100      101      11000    11001    11010    11011    11100    11101    11110    111110   111111  
F(x,13)  0        100      101      11000    11001    11010    11011    11100    11101    111100   111101   111110   111111  
F(x,14)  0        100      101      11000    11001    11010    11011    11100    111010   111011   111100   111101   111110   111111  
F(x,15)  0        100      101      11000    11001    11010    11011    111000   111001   111010   111011   111100   111101   111110   111111  

nneonneoによって指し示されるように、F(7,8)のは、111110それは長さ6を有しており、「未満のため、間違っている2*n(x)」を意味未満6
— fgrieu
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.