“그리드 채우기”문제


36

간단한 규칙이지만 사소한 알고리즘을 사용하는 것은 쉽지 않습니다. :-)

태스크

공백으로 구분 된 정수 형식으로 입력하십시오.

N A B S

여기서 N은 A와 B 사이의 고유 한 숫자 (정수)로 채워진 2D 정사각 행렬의 측면 길이입니다 . 이 행렬의 각 행과 열에 대한 합은 항상 같습니다. S. (즉, 행렬은 준 마법의 사각형입니다.)

노트 :

모든 숫자는 양수입니다. 예외는 A이며 0 일 수 있습니다.

에 대한

3 1 10000 2015

유효한 해결책은

여기에 이미지 설명을 입력하십시오

에 대한

8 1 300 500

유효한 해결책은

여기에 이미지 설명을 입력하십시오

산출

출력은 ASCII 테이블이어야합니다. 위의 첫 번째 예에 대한 예 :

 384  159 1472
1174  499  342
 457 1357  201

공백으로 채워진 오른쪽 정렬 정수 각 열의 너비는 해당 열에서 가장 큰 정수의 너비입니다.

채점

이것은 이므로 바이트 단위의 가장 짧은 코드가 이깁니다. 표준 허점이 적용됩니다 (특히이 문제를 해결하기 위해 내장 된 것). 잘못되거나 불가능한 입력 (음수 포함)에 신경 쓸 필요가 없습니다. 위의 두 번째 예에 대한 답변 (필수)으로 샘플 출력을 제공하십시오.


1
A와 B가 올바르게 합산되고 고유해질 때까지 A와 B 사이의 난수를 생성 할 수 있습니까?
lirtosiast

그냥 확인, A, B, 및 N음수가 될 수 있습니까?
xnor

2
minxomat, 나는 그것이 내가 생각해 낼 수있는 최선의 해결책이라고 말하지 않고, 그것이 가장 짧을 수도 있다고 말하고 있습니다.
lirtosiast

3
@LuisMendo 작업에 따라 샘플 출력을 생성해야합니다. 무차별 대입 방식으로 평생 관리 할 수 ​​있다면 감동 할 것입니다. :-). 나는 그것을 배제 할 수는 있지만 가장 인기있는 솔루션 (GA)은 여전히 ​​임의성을 포함하기 때문에 너무 모호합니다. 또한 누군가 솔루션을 이미 작업 할 때 규칙을 변경하고 싶지 않습니다.
mınxomaτ

1
@minxomat 당신의 세가지 주장은 모두 아주 좋은 점입니다 :-)
Luis Mendo

답변:


19

CJam, 119 91 바이트

q~:M;),>:R;(:L{{R{ML)d/-Y#)mr}$L/L<2{{M1$:+-+}%z}*:U:+__O|=R*-}gU{:s_:,:e>f{Se[}}%zSf*N*}M?

이것은 아마도 정확하고 비 결정적 접근 방식입니다.

내 데스크탑에서 두 번째 테스트 사례는 일반적으로 10 분 이내에 완료됩니다.

첫 번째 경우는 즉시 완료됩니다. CJam 통역사 에서 온라인으로 사용해보십시오 .

샘플 런

$ cjam grid.cjam <<< '8 1 300 500'
77  66  37 47  56  46 86  85
63 102  70 72  49  54 81   9
62  69  58 57  71  17 48 118
64  65  67 87  53  44 80  40
73  60  55 89  51  76 84  12
68  59  28 78  74  38 50 105
61  75  52 43 125  83 42  19
32   4 133 27  21 142 29 112

생각

시간 제한이 없으면 유효한 사각형을 찾을 때까지 무작위로 사각형을 생성 할 수 있습니다. 이 접근법은 두 가지 최적화를 추가하여이 아이디어를 기반으로합니다.

  • 측면 길이 N 의 의사 난수 생성 제곱 대신 측면 길이 N-1의 제곱을 생성 하고 행 하나에 합이 SN × (N-1) 사각형 을 형성하기 위해 하나의 열을 추가 한 다음 하나의 행을 제곱을 형성합니다. 측면 길이 N 그 열의 합이 S를 .

    모든 열의 요소 합이 NS 이고 첫 번째 N-1 행 의 요소 합 이 (N-1) S 이므로 마지막 행에도 합 S가 있습니다.

    그러나 마지막 행과 열의 모든 요소가 고유하거나 [A ... B] 범위에 속한다고 보장 할 수 없으므로이 프로세스는 잘못된 행렬을 생성 할 수 있습니다 .

  • [A ... B] 에서 고유 한 정수의 제곱 과 측면 길이 N-1 을 무작위로 균일하게 선택하면 너무 오래 걸립니다. 우리는 어떻게 든 이전 글 머리표에 자세히 설명 된 프로세스를 적용한 후 측면 길이 N 의 유효한 제곱이 될 가능성이 높은 제곱의 우선 순위를 정해야 합니다.

    각 행과 열의 합이 S 의 값을 가져야하는 경우 해당 요소의 평균은 S / N 입니다. 따라서 해당 평균에 가까운 요소를 더 많이 선택하면 기회가 증가합니다.

    [A ... B]의I 에 대해 , 우리는 0(I-S / N) 2 + 1 사이에서 실수를 의사 랜덤하게 선택하고 [A ... B] 의 요소를 선택된 부동 소수점으로 정렬합니다 . 우리는 첫 번째 N 2 숫자를 유지하고 정사각형으로 읽는 순서대로 놓습니다.

    각 단계에서 0(I-S / N) 2 + 1 사이의 모든 실수의 완벽하게 균일 한 분포를 가정하면 , 모든 제곱은 선택 될 확률이 0이 아니므로 프로세스가 결국 완료됩니다.

암호

q~          e# Read all input from STDIN and evaluate it.
:M;         e# Save "S" in M and discard it from the stack.
),>:R;      e# Transform "A B" into [A ... B], save in R and discard.
(:L         e# Save "N - 1" in L and keep it on the stack.
{           e# If L is non-zero:
  {         e#   Do:
    R{      e#     For each I in R:
      ML)d/ e#       Compute M/Double(L+1).
      -Y#   e#       Subtract the result from I and square the difference.
      )mr   e#       Add 1 and pick a non-negative Double below the result.
    }$      e#     Sort the values of I according to the picks.
    L/      e#     Split the shuffled R into chunks of length L.
    L<      e#     Keep only the first L chunks.
    2{      e#     Do twice:
      {     e#       For each row of the  L x L array.
        M1$ e#       Push M and a copy of the row.
        :+- e#       Add the integers of the row and subtract their sum from M.
        +   e#       Append the difference to the row.
      }%    e#
      z     e#       Transpose rows and columns.
    }*      e#
    :U:+    e#     Save the result in U and concatenate its rows.
    __O|    e#     Push two copies. Deduplicate the second copy.
    =R*     e#     Push R if all elements are unique, an empty array otherwise.
    -       e#     Remove the result's elements from U's elements.
  }g        e#   If the resulting array is non-empty, repeat the loop.
  U{        e#   For each row in U:
    :s      e#     Convert its integers into strings.
    _:,     e#     Copy and replace each string with its length.
    :e>     e#     Compute the maximum length.
    f{      e#     For each integer, push the maximum length; then
      Se[   e#       Left-pad the integer with spaces to that length.
    }       e#
  }%        e#
  z         e#   Transpose rows with columns.
  Sf*N*     e#   Join columns by spaces, rows by linefeeds.
}M?         e# Else, push M.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.