고유 한 세트를 만드는 배열 수


11

이 질문에는 목표가 상당히 다르지만 합계에 맞는 배열 찾기 와 비슷한 설정 이 있습니다.

Alength 배열 을 고려하십시오 n. 배열은 양의 정수만 포함합니다. 예를 들어 A = (1,1,2,2). f(A)비어 있지 않은 연속 된 모든 하위 배열의 합 집합을 정의합시다 A. 이 경우 f(A) = {1,2,3,4,5,6}. 생산 단계 f(A) 는 다음과 같습니다.

의 하위 배열은 A입니다 (1), (1), (2), (2), (1,1), (1,2), (2,2), (1,1,2), (1,2,2), (1,1,2,2). 각각의 합계는 1,1,2,2,2,3,4,4,5,6입니다. 따라서이 목록에서 얻은 세트는 {1,2,3,4,5,6}입니다.

같은 길이의 다른 배열이없는 경우 배열을 반대로 한 경우를 제외하고 A 고유 한 배열을 호출합니다 . 예를 들어, 동일한 합계 세트를 생성하는 다른 길이 배열은 없습니다 .Bf(A) = f(B)Af((1,2,3)) = f((3,2,1)) = {1,2,3,5,6}3

우리는 요소가 주어진 정수 s또는 배열 인 배열 만 고려할 것 s+1입니다. 예를 s=1들어 배열에 1and 만 포함되는 경우 2.

직무

작업은 주어진 위해 n그리고 s그 길이의 독특한 배열의 수를 계산하는 것입니다. 과 s사이에 있다고 가정 할 수 있습니다 .19

배열 자체와 배열의 반대 방향을 세지 않아야합니다.

s = 1대답은 항상 n+1입니다.

s = 2에서 계산 된 답변 n = 1은 다음과 같습니다.

2,3,6,10,20,32,52,86

s = 8에서 계산 된 답변 n = 1은 다음과 같습니다.

2,3,6,10,20,36,68,130

점수

주어진 n코드의 경우 sfrom에서 모든 값에 대한 답변을 출력해야 1합니다 9. n1 분 안에 완료되는 최고 점수입니다 .

테스팅

우분투 컴퓨터에서 코드를 실행해야하므로 코드를 컴파일하고 실행하는 방법에 대해 가능한 한 자세한 지침을 포함하십시오.

리더 보드

  • Rust의 Anders Kaseorg의 n = 24 (34 초)
  • 깨끗한 상태의 Ourous에 의한 n = 16 (36 초)
  • Common Lisp 에서 JRowan의 n = 14 (49 초)

s = 8이면 8과 9의 가능한 모든 조합으로 구성된 배열입니다.
JRowan

@JRowan 아니요. 다른 배열과 같은 합계 집합을 가진 배열은 계산하지 않습니다.
Anush

이 부분은 약간 혼란 스럽습니다. 우리는 요소가 주어진 정수 s 또는 s + 1 인 배열 만 고려할 것입니다. 예를 들어, s = 1 인 경우 배열에는 1과 2 만 포함됩니다. 따라서 n이 2이고 s가 3 인 경우 테스트 할 배열은 무엇입니까?
JRowan

[3,3]은 어떻습니까? 현재 목록의 반대를 제거하는 중입니다. 예. [3,4]-> [4,3]
JRowan

2
@RosLuP 첫째, 당신 은 다른 질문 에 그것을 게시하고 , 둘째, [3, 5, 4]는 부분 집합이지만 [3, 5, 1, 4] 의 부분 배열아닙니다 .
Anders Kaseorg

답변:


5

, n ≈ 24

편리한 reverse_bits기능을 위해 야간 녹이 필요 합니다. rustc -O unique.rs(예)로 컴파일 하고 실행하십시오 ./unique 24.

#![feature(reverse_bits)]
use std::{collections::HashMap, env, mem, process};

type T = u32;
const BITS: u32 = mem::size_of::<T>() as u32 * 8;

fn main() {
    let args = env::args().collect::<Vec<_>>();
    assert!(args.len() == 2);
    let n: u32 = args[1].parse().unwrap();
    assert!(n > 0);
    assert!(n <= BITS);
    let mut unique = (2..=9).map(|_| HashMap::new()).collect::<Vec<_>>();
    let mut sums = vec![0 as T; n as usize];
    for a in 0 as T..=!0 >> (BITS - n) {
        if a <= a.reverse_bits() >> (BITS - n) {
            for v in &mut sums {
                *v = 0;
            }
            for i in 0..n {
                let mut bit = 1;
                for j in i..n {
                    bit <<= a >> j & 1;
                    sums[(j - i) as usize] |= bit;
                }
            }
            for s in 2..=9 {
                let mut sums_s =
                    vec![0 as T; ((n + (n - 1) * s) / BITS + 1) as usize].into_boxed_slice();
                let mut pos = 0;
                let mut shift = 0;
                let mut lo = 0;
                let mut hi = 0;
                for &v in &sums {
                    lo |= v << shift;
                    if BITS - shift < n {
                        hi |= v >> (BITS - shift);
                    }
                    shift += s;
                    if shift >= BITS {
                        shift -= BITS;
                        sums_s[pos] = lo;
                        pos += 1;
                        lo = hi;
                        hi = 0;
                    }
                }
                if lo != 0 || hi != 0 {
                    sums_s[pos] = lo;
                    pos += 1;
                    if hi != 0 {
                        sums_s[pos] = hi;
                    }
                }
                unique[s as usize - 2]
                    .entry(sums_s)
                    .and_modify(|u| *u = false)
                    .or_insert(true);
            }
        }
    }
    let mut counts = vec![n + 1];
    counts.extend(
        unique
            .iter()
            .map(|m| m.values().map(|&u| u as T).sum::<T>())
            .collect::<Vec<_>>(),
    );
    println!("{:?}", counts);
    process::exit(0); // Avoid running destructors.
}

감사합니다. 약 90 초 안에 n = 25 동안 완료됩니다. 그러나 주요 문제는 내 8GB RAM의 70 %를 사용한다는 것입니다.
Anush

나는 갑자기 무언가에 대해 걱정했다. 배열이 다른 모든 가능한 배열과 관련하여 고유하거나 값이 s있고 그 s+1안에 배열이 있는지 확인 하고 있습니까?
Anush

@Anush 예, 속도를 위해 메모리 사용을 교환했습니다. 내가 값을 가진 독특한 WRT 다른 배열 인 배열을 믿는다 ss + 1는 그 차이를 만들 것입니다 여부를 즉시 명확하지 비록, (당신이 그 우리가 고려할 수있는 유일한 배열 말했습니다부터).
Anders Kaseorg

1
내일이 문제를 해결해야한다고 생각합니다. 배열 1,1,2,2 및 1,1,1,3은 모두 합계 1,2,3,4,5,6을 제공합니다. 그러나 전자는 1과 2 만있는 배열 중에서 고유하지 않으므로 지금 차이가 나는 경우 약간 혼란 스럽습니다.
Anush

2
@Anush 차이를 만듭니다. [1, 2, 2, 2]의 합은 길이가 4의 1과 2 인 배열 중에서 고유하지만 [1, 1, 2, 3]의 합과 같습니다.
Anders Kaseorg

2

공통 리스프 SBCL, N = 14

호출 기능 (goahead ns)

    (defun sub-lists(l m &optional(x 0)(y 0))
  (cond; ((and(= y (length l))(= x (length l)))nil)
        ((= y (length l))m)
        ((= x (length l))(sub-lists l m 0(1+ y)))
    (t (sub-lists l (cons(loop for a from x to (+ x y)

             when (and(nth (+ x y)l)(nth a l)(< (+ x y)(length l)))
                ;   while (nth a l)
             ;while(and(< (+ x y)(length l))(nth a l))
                    collect (nth a l))m) (1+ x)y))
    ))
(defun permutations(size elements)
  (if (zerop size)'(())
 (mapcan (lambda (p)
                    (map 'list (lambda (e)
                           (cons e p))
                         elements))
     (permutations (1- size) elements))))
(defun remove-reverse(l m)
  (cond ((endp l)m)
    ((member (reverse (first l))(rest l) :test #'equal)(remove-reverse (rest l)m))
    (t (remove-reverse (rest l)(cons (first l)m)))))
(defun main(n s)
  (let((l (remove-reverse (permutations n `(,s ,(1+ s)))nil)))

  (loop for x in l
     for j = (remove 'nil (sub-lists x nil))
       collect(sort (make-set(loop for y in j
        collect (apply '+ y))nil)#'<)
     )
  ))
(defun remove-dups(l m n)
  (cond ((endp l)n)
        ((member (first l) (rest l) :test #'equal)(remove-dups(rest l)(cons (first l) m) n))
    ((member (first l) m :test #'equal)(remove-dups(rest l)m n))
    (t(remove-dups (rest l) m (cons (first l) n))))

  )
(defun goahead(n s)
  (loop for a from 1 to s
  collect(length (remove-dups(main n a)nil nil))))
(defun make-set (L m)
  "Returns a set from a list. Duplicate elements are removed."
  (cond ((endp L) m)
    ((member (first L) (rest L)) (make-set (rest L)m))
    ( t (make-set (rest L)(cons (first l)m)))))

여기에 런타임이 있습니다

CL-USER> (time (goahead 14 9))
Evaluation took:
  34.342 seconds of real time
  34.295000 seconds of total run time (34.103012 user, 0.191988 system)
  [ Run times consist of 0.263 seconds GC time, and 34.032 seconds non-GC time. ]
  99.86% CPU
  103,024,254,028 processor cycles
  1,473,099,744 bytes consed

(15 1047 4893 6864 7270 7324 7328 7328 7328)
CL-USER> (time (goahead 15 9))
Evaluation took:
  138.639 seconds of real time
  138.511089 seconds of total run time (137.923824 user, 0.587265 system)
  [ Run times consist of 0.630 seconds GC time, and 137.882 seconds non-GC time. ]
  99.91% CPU
  415,915,271,830 processor cycles
  3,453,394,576 bytes consed

(16 1502 8848 13336 14418 14578 14594 14594 14594)

이것을 어떻게 실행합니까? 코드를 파일로 복사하여 sbcl어떻게 든 호출 합니까?
Anush

1
나는 emacs와 slime을 사용하지만 test.lisp와 sbcl promp에 디렉토리 호출 (load "test.lisp")에서 파일을 넣은 다음 맨 아래에있는 함수를 호출 할 수있다
JRowan

2

깨끗한

확실히 가장 효율적인 접근 방식은 아니지만 순전 한 값 기준 필터가 얼마나 잘 작동하는지 알고 싶습니다.

그러나이 방법을 사용하면 여전히 약간의 개선이 이루어지고 있습니다.

module main
import StdEnv, Data.List, System.CommandLine

f l = sort (nub [sum t \\ i <- inits l, t <- tails i])

Start w
	# ([_:args], w) = getCommandLine w
	= case map toInt args of
		[n] = map (flip countUniques n) [1..9]
		_ = abort "Wrong number of arguments!"

countUniques 1 n = inc n
countUniques s n = length uniques
where
	lists = [[s + ((i >> p) bitand 1) \\ p <- [0..dec n]] \\ i <- [0..2^n-1]]
	pairs = sortBy (\(a,_) (b,_) = a < b) (zip (map f lists, lists))
	groups = map (snd o unzip) (groupBy (\(a,_) (b,_) = a == b) pairs)
	uniques = filter (\section = case section of [a, b] = a == reverse b; [_] = True; _ = False) groups

라는 파일 main.icl에 배치하거나 맨 위 줄을로 변경하십시오 module <your_file_name_here>.

로 컴파일하십시오 clm -h 1500m -s 50m -fusion -t -IL Dynamics -IL StdEnv -IL Platform main.

제목의 링크 또는 여기 에서 최신 버전의 TIO (및 자신) 버전을 사용할 수 있습니다 .


이 코드가 올바른 출력을 제공한다고 생각하지 않습니다. 나는 s = 8로 시험해 보았고 [9,86,126,130,130,130,130,130,130]
Anush

@Anush 흠 나는 그것을 테스트했다는 것을 알고있다. 나는 그와 게시 된 것 사이에 무엇이 바뀌 었는지 볼 것이고, 몇 시간을 주면 휴식 시간에 할 수 있습니다.
OUurous

@Anush 왜 제공하고 s있습니까? " 주어진 n에 대해 코드는 s의 모든 값에 대한 답변을 1에서 9까지 출력해야합니다."라는 질문에
OUurous

1
나는 그것이 당신이 뇌 동결이라고 부르는 것이라고 생각합니다. :) 이제 코드를 작성하겠습니다.
Anush
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.