Hitung Jarak Hausdorff

21

pengantar

The Hausdorff jarak mengukur perbedaan antara dua himpunan bagian dari ruang metrik. Secara intuitif, ruang metrik hanya beberapa set dengan fungsi jarak built-in; dalam tantangan ini, kita akan menggunakan bilangan asli dengan jarak biasa d(a, b) := abs(a - b). Jarak Hausdorff antara dua set hingga tidak kosong Adan Bdiberikan oleh

max(max(min(d(a, b) for b in B) for a in A),
    max(min(d(a, b) for a in A) for b in B))

dalam notasi seperti Python. Jarak Hausdorff dapat dihitung dengan menemukan elemen Ayang jarak ke elemen terdekat Bmaksimal, dan elemen Byang jaraknya ke elemen terdekat Amaksimal, dan kemudian mengambil maksimum jarak ini. Dengan kata lain, jika jarak Hausdorff adalah d, maka setiap elemen Aberada dalam jarak dbeberapa elemen B, dan sebaliknya.

Memasukkan

Input Anda adalah satu daftar bilangan bulat. Ini hanya berisi elemen-elemen 0,1,2,3, yang menandakan apakah indeks daftar yang diberikan adalah elemen yang bukan Aatau bukan B, hanya A, saja B, atau keduanya Adan B. Misalnya, input [0,1,1,0,2,3]berarti bahwa A = {1,2,5}dan B = {4,5}, jika kami menggunakan pengindeksan berbasis 0 (yang tidak membuat perbedaan, karena metrik kami adalah terjemahan invarian).

Keluaran

Output Anda adalah jarak Hausdorff antara Adan B; dalam contoh di atas, itu 3. Jika salah satu set kosong, maka jaraknya tidak ditentukan, dan Anda akan kembali -1.

Aturan

Anda dapat menulis program atau fungsi lengkap. Hitungan byte terendah menang, dan celah standar tidak diizinkan.

Uji Kasus

[] -> -1
[0] -> -1
[0,1,0] -> -1
[2,0,0,2] -> -1
[0,1,2,3] -> 1
[0,3,3,0,0,0,0,3] -> 0
[1,0,0,1,0,0,1,3,1] -> 7
[1,0,0,0,0,3,0,0,0,0,2] -> 5
[0,1,1,3,1,3,2,1,1,3,0,3] -> 2
[2,2,2,1,2,0,3,1,3,1,0,3] -> 3
[1,3,0,2,0,2,2,1,0,3,2,1,1,2,2] -> 2
[1,0,1,1,2,0,1,2,3,1,0,0,0,1,2,0] -> 4
Zgarb
sumber
Dalam persamaan Anda, saya percaya itu terlalu lama, sebagaimana max(max(min(d(a, b) for b in B) for a in A))seharusnya sudah cukup. Ini karena d(a,b)mengembalikan nilai absolut, dan karena itu kedua fungsi maks akan mengembalikan angka yang sama setiap waktu.
Nathan Merrill
6
@NathanMerrill Mungkin saja setiap elemen Asangat dekat dengan salah satunya B, tetapi ada elemen yang Bsangat jauh dari A(misalnya, jika Amerupakan subset dari B). Dalam hal itu, rumus pendeknya salah.
Zgarb

Jawaban:

7

CJam, 53 52 46 38 37 byte

3,q~f{f&:L,{L=},}$~ff{-z}_z+::e<W+:e>

Mengambil input pada STDIN sebagai larik gaya CJam:

[0 1 2 3]

Berikut ini adalah test harness yang mengubah semua test case ke format ini dan menjalankan kodenya. Meskipun hasilnya ada di bidang input, hasilnya tidak digunakan oleh kode (hapus jika Anda tidak mempercayai saya :)).

Penjelasan

Pertama, kami mengurai input untuk mendapatkan dua set A dan B:

3,q~f{f&:L,{L=},}$~
3,                  "Push [0 1 2]. 1 is for A, 2 is for B, and 0 we can luckily ignore
                     as we'll see later.";
  q~                "Read and evaluate the input.";
    f{          }   "Map this block onto the [0 1 2] array, copying in the input for
                     each iteration.";
      f&:L          "Take the bitwise AND with each element of the input and store the
                     result in L.";
          ,{  },    "Get the length N, and filter the range [0 .. N-1] by evaluating
                     the block for each element.";
            L=      "Check if the bitwise AND at that index yielded something non-zero.
                     This gives an empty array for 0, A for 1 and B for 2.";
                 $  "Sort the three arrays. This has two important effects: a) it moves
                     the empty array resulting from 0 to the front, and b) if only one
                     of A and B is empty, it moves the non-empty one to the end.";
                  ~ "Unwrap the array, dumping all three sets on the stack.";

Dan sekarang kami menemukan perbedaan absolut dan memilih maks menit:

ff{-z}_z+::e<W+:e>
ff{-z}             "Turn A and B into a matrix of absolute differences.";
      _z           "Duplicate and transpose.";
        +          "Add the two together, so I've got one row of distances for
                    each element in either A or B.";
         ::e<      "Find the minimum of each row.";
             W+    "Add a -1 in case one set was empty.";
               :e> "Get the overall maximum.";

Perhatikan bahwa kami telah menyimpan array kosong yang dihasilkan dari awal 0di bagian bawah tumpukan sepanjang waktu, tetapi array kosong tidak berkontribusi apa pun pada output.

Martin Ender
sumber
5

CJam, 57 56 52 byte

Saya pikir ini bisa sedikit golf, tapi begini:

q~ee_{W=2%},\{W=1>},]0ff=_W%]{~ff-{:z$1<~}%W+$W=}/e>

Input masuk seperti daftar gaya CJam, mis.

[1 0 0 0 0 3 0 0 0 0 2]

5

Cara kerjanya :

Kode ini dibagi menjadi dua bagian:

Parsing input ke dalam daftar Adan B:

q~ee_{W=2%},\{W=1>},]0ff=_W%]
q~                               "Eval the input array";
  ee                             "Enumerate and prepend index with each element. For ex:
                                  [5 3 6]ee gives [[0 5] [1 3] [2 6]]";
    _{W=2%},                     "Make a copy and filter out elements with value 1 or 3";
            \{W=1>},             "On the original, filter elements with value 2 or 3";
                    ]            "Wrap stack in an array. Stack right now contains
                                  enumerated A and B in an array";
                     0ff=        "Get the index of the enumerated arrays. Stack is [A B]";
                         _W%     "Make a copy and swap order. Stack is now [A B] [B A]";
                            ]    "Wrap this in an array";

Melakukan tindakan yang diperlukan pada dua pasang Adan B:

{~ff-{:z$1<~}%W+$W=}/e>
{                  }/            "Run this loop for both the pairs, [A B] and [B A]"
 ~ff-                            "Unwrap [A B] and take difference of every pair";
     {      }%                   "For each row in the matrix difference";
      :z$                        "abs each term and then sort";
         1<~                     "Take only the first element of the array";
              W+                 "Add -1 to compensate for an empty array";
                $W=              "Take max";
                     e>          "Take max of the two maximums";

Cobalah online di sini

Pengoptimal
sumber
5

Lua, 235 byte

Jelas bukan pemenang, tetapi setidaknya tantangan yang menyenangkan.

A={}B={}c={}d={}m=math p=m.min q=m.max u=unpack for k=1,#arg do for h=0,1 do if
arg[k]/2^h%2>=1 then A[#A+1]=k for i=1,#B do l=m.abs(B[i]-k)d[i]=p(d[i]or
l,l)c[#A]=p(c[#A]or l,l)end end A,B=B,A c,d=d,c end end
print(q(q(-1,u(c)),u(d)))

Input berfungsi seperti ini:

lua hausdorff.lua <space-separated-sequence>

... dan inilah skrip pengujian:

local testcase = arg[1] or 'hausdorff.lua'
print('testing '..testcase)
local function run(args) 
    return function(expected)
        local result = tonumber(
            io.popen('lua.exe '..testcase..' '..args):read'*a':match'%S+')
        print(args..' -> '..expected..' :: '..result)
        assert(result == expected,
            ("for input %q expected %s but got %s"):format(
                args, expected, result))
    end
end
run''(-1)
run'0'(-1)
run'0 1 0'(-1)
run'2 0 0 2'(-1)
run'0 1 2 3'(1)
run'0 3 3 0 0 0 0 3'(0)
run'1 0 0 1 0 0 1 3 1'(7)
run'1 0 0 0 0 3 0 0 0 0 2'(5)
run'0 1 1 3 1 3 2 1 1 3 0 3'(2)
run'2 2 2 1 2 0 3 1 3 1 0 3'(3)
run'1 3 0 2 0 2 2 1 0 3 2 1 1 2 2'(2)
run'1 0 1 1 2 0 1 2 3 1 0 0 0 1 2 0'(4)

... menghasilkan ...

testing hausdorff.lua
 -> -1 :: -1
0 -> -1 :: -1
0 1 0 -> -1 :: -1
2 0 0 2 -> -1 :: -1
0 1 2 3 -> 1 :: 1
0 3 3 0 0 0 0 3 -> 0 :: 0
1 0 0 1 0 0 1 3 1 -> 7 :: 7
1 0 0 0 0 3 0 0 0 0 2 -> 5 :: 5
0 1 1 3 1 3 2 1 1 3 0 3 -> 2 :: 2
2 2 2 1 2 0 3 1 3 1 0 3 -> 3 :: 3
1 3 0 2 0 2 2 1 0 3 2 1 1 2 2 -> 2 :: 2
1 0 1 1 2 0 1 2 3 1 0 0 0 1 2 0 -> 4 :: 4
lalunomor
sumber
4

Pyth, 43 40 39 38 byte

J+m0yQQLq3.|Fb?eS.e&Yfy:J-kT+hkT0JyJ_1

Algoritme saya beroperasi langsung pada string input dan tidak pernah mengonversi angka ini. Ini hanya menghitung sekali maksimal dan tidak pernah minimum.

Terima kasih kepada @isaacg untuk menghemat satu byte.

Cobalah secara online: Pyth Compiler / Executor

Penjelasan:

Pertama saya akan memasukkan banyak nol di depan input.

          implicit: Q = input()
    yQ    powerset(Q)
  m0yQ    map each element of the powerset to 0 (creates 2^Q zeros, I said lots)
 +    Q   zeros + Q
J         assign to J

Lalu saya mendefinisikan fungsi pembantu y, yang memberi tahu jika indeks daftar (seperti input satu) muncul di kedua set A dan BEg y([0, 1, 0, 0, 1, 1]) = False, tetapi y([0, 1, 0, 2]) = y([3]) = True.

Lq3.|Fb
L          define a function y(b), which returns _
   .|Fb       fold b by bitwise or
 q3            == 3

Setelah itu saya periksa dulu apakah hasilnya -1.

?...yJ_1   print ... if numbers appear in both sets (`yJ`) else -1   

Sekarang untuk hal-hal menarik:

  .e              J    map each pair k,Y in enumerate(J) to:
    &Y                   Y and ... (acts as 0 if Y == 0 else ...)
      f          0       find the first number T >= 0, where:
       y                    indices appear in both sets in the substring
        :J-kT+hkT           J[k-T:k+T+1]
eS                     sort and take last element (maximum)

Perhatikan, bahwa saya akan selalu menemukan nomor T, karena saya sudah tahu bahwa indeks muncul di kedua set dalam daftar J. Angka tersebut maksimal length(Q). Ini juga alasan untuk memasukkan angka nol. Jika ada setidaknya length(Q)nol yang dimasukkan, k-Tselalu >= 0, yang diperlukan untuk mengiris daftar. Jadi mengapa saya memasukkan 2^length(Q)angka nol dan bukan length(Q)angka nol? Dalam test-case []saya membutuhkan setidaknya 1 nol, jika tidak yJakan mengembalikan kesalahan.

Jakube
sumber
><Cabsama dengan :Cba.
isaacg
Untung kasus uji tidak memasukkan input besar ...
TLW
3

Mathematica, 88 byte

Max[Min/@#,Min/@Thread@#,-1]/.∞->-1&@Outer[Abs[#-#2]&,p=Position;p[#,1|3],p[#,2|3],1]&
alephalpha
sumber
1
Jawaban yang sangat bagus Untuk menemukan jarak Hausdorff yang lebih umum, seseorang dapat menggunakan m=MaxValue;Max[m[RegionDistance[#[[1]],s],s\[Element]#[[2]]]/.m[__]->-1&/@{#,Reverse@c}]& yang kemudian dapat diterapkan pada objek multidimensi seperti itu%@{Sphere[],Line[{{1,1,0},{3,3,3}}]}
Kelly Lowder
3

Haskell, 145 126 124 byte

s t x=[e|(e,i)<-zip[0..]x,t i]
d#e=maximum[minimum[abs$i-j|j<-e]|i<-d]
[]%_= -1
_%[]= -1
d%e=max(d#e)$e#d
f x=s(>1)x%s odd x

Uji coba:

*Main> map f [[], [0], [0,1,0], [2,0,0,2], [0,1,2,3],
              [0,3,3,0,0,0,0,3], [1,0,0,1,0,0,1,3,1],
              [1,0,0,0,0,3,0,0,0,0,2], [0,1,1,3,1,3,2,1,1,3,0,3],
              [2,2,2,1,2,0,3,1,3,1,0,3],
              [1,3,0,2,0,2,2,1,0,3,2,1,1,2,2],
              [1,0,1,1,2,0,1,2,3,1,0,0,0,1,2,0]]

[-1,-1,-1,-1,1,0,7,5,2,3,2,4]

smemfilter bilangan asli sesuai dengan predikat tdan daftar input x. #menghitung jarak maksimum parameter ddan e. %menangkap set kosong A atau B atau mengambil maksimum akhir dari d#edan e#d. fadalah fungsi utama yang memanggil %dengan set A dan B.

Sunting: @Zgarb menemukan banyak byte untuk disimpan; @ ali0sha yang lain 2. Terima kasih!

nimi
sumber
The mod 2tampaknya tidak perlu. Anda juga dapat mengambil manfaat dari tidak mendefinisikan adan bsecara eksplisit.
Zgarb
Anda dapat menyimpan 2 byte dengan []%_= -1- tetapi Anda mengalahkan upaya saya dengan tangan ini :)
alexander-brett
3

Perl, 56 55

Menambahkan +2 untuk -lp.

Daftar input harus diberikan pada stdin tanpa spasi, misalnya:

echo 1011201231000120 | perl -lp hausdorf.pl

hausdorf.pl:

s%%$z=$_&=$p|=$'|P.$p;$q+=!!y/12/3/%eg;$_=$z=~3?$q:-1

Untuk mendukung spasi di antara elemen-elemen dari daftar input cukup bagi final $qdengan 2 untuk biaya 2 stroke

Ton Hospel
sumber
2

Python 2, 124

Ini pasti terasa suboptimal. Baiklah.

lambda a,E=enumerate:-min([1]+[~l*(n<3)for i,n in E(a)for l,_ in E(a)if{0}|set(n*a+n/3*[5])>{0,n}>=set(a[max(i-l,0):i-~l])])
feersum
sumber
1

APL (49)

{(⊂⍬)∊∆←(↓2 2⊤⍵)/¨⊂⍳⍴⍵:¯1⋄⌈/{⌈/⌊/⍵}¨(+,⍉¨)|∘.-/∆}

Testcases:

      ({(⊂⍬)∊∆←(↓2 2⊤⍵)/¨⊂⍳⍴⍵:¯1⋄⌈/{⌈/⌊/⍵}¨(+,⍉¨)|∘.-/∆} ¨ testcases) ,⍨ '→',⍨ ↑ ⍕¨testcases
                               → ¯1
0                              → ¯1
0 1 0                          → ¯1
2 0 0 2                        → ¯1
0 1 2 3                        →  1
0 3 3 0 0 0 0 3                →  0
1 0 0 1 0 0 1 3 1              →  7
1 0 0 0 0 3 0 0 0 0 2          →  5
0 1 1 3 1 3 2 1 1 3 0 3        →  2
2 2 2 1 2 0 3 1 3 1 0 3        →  3
1 3 0 2 0 2 2 1 0 3 2 1 1 2 2  →  2
1 0 1 1 2 0 1 2 3 1 0 0 0 1 2 0→  4

Penjelasan:

  • ⍳⍴⍵: dapatkan daftar angka dari 1 hingga panjang daftar input
  • ↓2 2⊤⍵: untuk setiap nilai dalam daftar input, dapatkan byte pertama dan byte kedua
  • ∆←(... )/⊂⍳⍴⍵: untuk kedua daftar byte, pilih nilai yang sesuai dari ⍳⍴⍵. Menyimpan ini dalam .
  • (⊂⍬)∊∆... :¯1: jika daftar ini berisi daftar kosong, kembali -1. Jika tidak:

  • |∘.-/∆: dapatkan perbedaan absolut antara setiap pasangan nilai, dengan memberikan matriks

  • (+,⍉¨): dapatkan salinan yang diputar dan tidak diputar dari matriks itu
  • {⌈/⌊/⍵}: untuk kedua matriks, dapatkan maksimum dari baris minimum
  • ⌈/: lalu dapatkan yang maksimal
marinus
sumber
@Optimizer: Saya entah bagaimana berhasil menyalin hasil tes dari versi sebelumnya yang memiliki bug. Kode itu sendiri sudah benar dan masih ada. Jika Anda tidak percaya kepada saya, coba di sini . (Perhatikan bahwa Anda harus memasukkan daftar satu elemen sebagai ,X, untuk membedakannya dari skalar X.)
marinus
Ah saya mengerti. malas saya untuk tidak pergi ke kompiler online dan menguji ..
Pengoptimal
1

Perl, 189 176 157B

Sekarang dengan status 500% lebih.

use List::Util qw'max min';@I=<>;sub f{$n=($n%2)+1;map{$I[$_]&$n?$_:()}0..$#I}sub i{@t=f;max map{$b=$_;min map{abs$_-$b}@t}f}$r=max i,i;print defined$r?$r:-1

Terbaca:

use List::Util qw'max min';
@I=<>;
sub f {
    $n = ($n%2) + 1;
    map { $I[$_] & $n ? $_ : () } 0..$#I
}
sub i {
    @t = f;
    max map {
        $b = $_;
        min map { abs $_ - $b } @t
    } f
}
$r = max i,i;
print defined $r ? $r : -1

Contoh penggunaan:

memasukkan

0
1
2
3

perl golf.pl < input

alexander-brett
sumber
0

Clojure, 167 byte

#(let[P apply F(fn[I](filter(fn[i](I(% i)))(range(count %))))A(F #{1 3})B(F #{2 3})d(fn[X Y](P min(for[x X](P max(for[y Y](P -(sort[x y])))))))](-(min(d A B)(d B A))))

Harus ada jalan yang lebih pendek ... Apakah ada?

NikoNyrh
sumber