하우스 도르프 거리 계산


21

소개

하우스 도르프 거리 메트릭 공간의 두 개의 서브 세트들 사이의 차이를 측정한다. 직관적으로, 미터법 공간은 내장 된 거리 기능으로 설정됩니다. 이 도전에서, 우리는 일반적인 거리를 가진 자연수를 사용할 것 d(a, b) := abs(a - b)입니다. 하우스 도르프의 두 비어 유한 집합 사이의 거리 A와는 B주어진다

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))

파이썬과 같은 표기법으로. Hausdorff 거리는 A가장 가까운 요소까지의 거리 B가 최대 인 요소와 B가장 가까운 요소까지의 거리 A가 최대 인 요소를 찾은 다음이 거리의 최대 값을 계산하여 계산할 수 있습니다 . 즉, Hausdorff 거리가 d인 경우의 모든 요소는 의 일부 요소의 A거리 내에 있으며 그 반대도 마찬가지입니다.dB

입력

입력은 단일 정수 목록입니다. 그것은 요소만을 포함 0,1,2,3리스트의 인덱스가 주어진 소자의 어느 쪽인지를 나타 내기, AB오직 AB또는 둘 모두 AB. 예를 들면, 입력 [0,1,1,0,2,3]수단 A = {1,2,5}B = {4,5}, 우리는 (로모 메트릭 변환 불변으로 아무런 차이가없는) 0 기반 인덱스를 사용하는 경우.

산출

귀하의 출력 사이의 하우스 도르프의 거리 AB; 위의 예에서는입니다 3. 두 세트 중 하나가 비어 있으면 거리가 정의되어 있지 않으므로를 반환해야 -1합니다.

규칙

전체 프로그램이나 함수를 작성할 수 있습니다. 가장 낮은 바이트 수가 이기고 표준 허점은 허용되지 않습니다.

테스트 사례

[] -> -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

귀하의 방정식에서, 나는 그것이 너무 길어야한다고 생각합니다 max(max(min(d(a, b) for b in B) for a in A)). 이는 d(a,b)절대 값을 반환하기 때문에 두 max 함수는 매번 같은 숫자를 반환합니다.
Nathan Merrill

6
@NathanMerrill의 모든 요소 A가 중 하나에 매우 가깝지만 매우 멀리 떨어져 B있는 요소가있을 수 B있습니다 A(예 A:의 하위 집합 인 경우 B). 이 경우 짧은 공식이 올바르지 않습니다.
Zgarb

답변:


7

CJam, 53 52 46 38 37 바이트

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

STDIN에 CJam 스타일 배열로 입력을받습니다.

[0 1 2 3]

다음은 모든 테스트 사례를이 형식으로 변환하고 코드를 실행 하는 테스트 하네스 입니다. 결과는 입력 필드에 있지만 코드에서 사용되지 않습니다 (믿지 않으면 제거하십시오 :).

설명

먼저 입력을 구문 분석하여 두 세트 A와 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.";

이제 절대 차이를 찾아 최대 값을 선택합니다.

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.";

빈 배열은 항상 0스택 맨 아래의 초기 결과로 유지 되지만 빈 배열은 출력에 아무런 영향을 미치지 않습니다.


5

CJam, 57 56 52 바이트

나는 이것이 약간 골프를 칠 수 있다고 생각하지만 여기에 간다.

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

입력은 CJam 스타일 목록과 같습니다 (예 :

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

5

작동 방식 :

코드는 두 부분으로 나뉩니다.

입력을 목록으로 구문 분석 A하고 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";

두 쌍에 필요한 작업 수행 AB:

{~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";

여기에서 온라인으로 사용해보십시오


5

루아, 235 바이트

확실히 승자는 아니지만 최소한 재미있는 도전입니다.

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)))

입력은 다음과 같이 작동합니다.

lua hausdorff.lua <space-separated-sequence>

... 그리고 여기에 테스트 스크립트가 있습니다 :

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)

... 생산

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

4

Pyth, 43 40 39 38 바이트

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

내 알고리즘은 입력 문자열에서 직접 작동하며 절대 숫자를 변환하지 않습니다. 최대 한 번만 계산하고 최소 한 번도 계산하지 않습니다.

1 바이트를 저장해 준 @isaacg에게 감사합니다.

온라인 사용해보기 : Pyth Compiler / Executor

설명 :

먼저 입력 앞에 많은 제로를 삽입합니다.

          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

그럼 도우미 함수 정의 y(입력과 같은)리스트의 인덱스가 두 세트 A 및 BEG에 나타나면 지시, y([0, 1, 0, 0, 1, 1]) = False있지만 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

그런 다음 먼저 결과가인지 확인합니다 -1.

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

이제 흥미로운 것들 :

  .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)

T목록 J의 두 세트 모두에 인덱스가 있음을 이미 알고 있으므로 항상 숫자를 찾을 것 length(Q)입니다. 숫자는 최대 입니다. 이것은 또한 0을 삽입하는 이유입니다. 적어도 length(Q)0이 삽입되어 k-T있으면 항상입니다 >= 0. 이는 목록 슬라이싱에 필요합니다. 그렇다면 왜 2^length(Q)0 대신 0을 삽입해야 length(Q)합니까? 테스트 사례 []에서 적어도 0이 필요합니다. 그렇지 않으면 yJ오류가 반환됩니다.


><Cab와 동일합니다 :Cba.
isaacg

테스트 케이스에 큰 입력이 포함되어 있지 않은 것이 좋습니다.
TLW

3

수학, 88 바이트

Max[Min/@#,Min/@Thread@#,-1]/.∞->-1&@Outer[Abs[#-#2]&,p=Position;p[#,1|3],p[#,2|3],1]&

1
아주 좋은 답변입니다. Hausdorff 거리에 대한보다 일반적인 발견을 m=MaxValue;Max[m[RegionDistance[#[[1]],s],s\[Element]#[[2]]]/.m[__]->-1&/@{#,Reverse@c}]& 위해 다차원 물체에 적용 할 수 있습니다%@{Sphere[],Line[{{1,1,0},{3,3,3}}]}
Kelly Lowder

3

하스켈, 145 (126) 124 바이트

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

시운전 :

*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]

s술어 t와 입력 목록 에 따라 자연수를 필터링합니다 x. #그것의 매개 변수의 최대 거리를 계산 d하고 e. %빈 세트 A 또는 B를 캐치 또는 마지막 최대를 취 d#ee#d. f호출하는 주요 기능입니다%세트 A와 B로 .

편집 : @ Zgarb는 저장할 바이트를 많이 발견했습니다. @ ali0sha 또 다른 2. 감사합니다!


mod 2불필요한 것으로 보인다. 또한 정의되지 혜택을 누릴 수 ab명시 적으로.
Zgarb

당신은 2 바이트를 절약 할 수 있습니다 []%_= -1-하지만 당신은 이것에 내 시도 손을 이길 :)
alexander-brett

3

펄, 56 55

에 +2가 추가되었습니다 -lp.

입력 목록은 공백없이 stdin에 제공되어야합니다. 예 :

echo 1011201231000120 | perl -lp hausdorf.pl

hausdorf.pl:

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

입력 목록의 요소 사이에 공백을 지원하려면 $q2 스트로크 비용으로 최종 을 2로 나눕니다.


2

파이썬 2, 124

이것은 확실히 차선책이라고 느낍니다. 오 잘

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])])

1

APL (49)

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

테스트 케이스 :

      ({(⊂⍬)∊∆←(↓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

설명:

  • ⍳⍴⍵: 1에서 입력 목록 길이까지의 숫자 목록을 가져옵니다.
  • ↓2 2⊤⍵: 입력 목록의 각 값에 대해 첫 번째 바이트와 두 번째 바이트를 가져옵니다.
  • ∆←(... )/⊂⍳⍴⍵: 두 바이트 목록 모두에서 해당 값을 선택하십시오 ⍳⍴⍵. 에 저장하십시오 .
  • (⊂⍬)∊∆... :¯1:이리스트에 빈리스트가 포함되어 있으면를 반환 -1합니다. 그렇지 않으면:

  • |∘.-/∆: 모든 값 쌍 사이의 절대 차이를 얻어 행렬을 제공합니다.

  • (+,⍉¨): 해당 행렬의 회전되고 회전되지 않은 복사본을 얻습니다.
  • {⌈/⌊/⍵}: 두 행렬 모두에 대해 최소 행의 최대 값을 얻습니다.
  • ⌈/: 그 최대 값을 얻습니다

@Optimizer : 어떻게 든 버그가있는 이전 버전의 테스트 결과를 복사했습니다. 코드 자체는 정확하고 여전히 그렇습니다. 당신이 저를 믿지 않는다면 여기 에서 시도 하십시오 . ( ,X스칼라와 구별하기 위해 로 한 요소 목록을 입력해야합니다 X.)
marinus

아 알 겠어요 게으른 온라인 컴파일러로 가서 테스트하지 마십시오 ..
Optimizer

1

펄, 189 176 157B

이제 상태가 500 % 증가합니다.

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

읽기 쉬운:

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

사용법 예 :

입력

0
1
2
3

perl golf.pl < input


0

클로저, 167 바이트

#(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))))

더 짧은 방법이 있어야합니다 ... 있습니까?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.