Порахуйте масиви, які складають унікальні набори


11

Це питання має аналогічний набір для пошуку масиву, який відповідає набору сум, хоча він і зовсім відрізняється від своїх цілей.

Розглянемо масив Aдовжини 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 унікальним, якщо немає іншого масиву Bтакої ж довжини, який f(A) = f(B), за винятком масиву, Aоберненого назад. Як приклад, f((1,2,3)) = f((3,2,1)) = {1,2,3,5,6}але не існує іншого масиву довжини, 3який б створював той самий набір сум.

Ми розглянемо лише масиви, де елементи є або заданим цілим числом, sабо s+1. Наприклад, якщо s=1масиви містили б лише 1і 2.

Завдання

Завдання, для даного nі sє підрахунок кількості унікальних масивів цієї довжини. Ви можете припустити, що sце між 1і 9.

Ви не повинні рахувати реверс масиву, а також сам масив.

Приклади

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коду слід вивести відповідь на всі значення від sз 1до 9. Ваш бал - це найвище значення, nза яке це завершується за одну хвилину.

Тестування

Мені потрібно запустити ваш код на моїй машині ubuntu, тому, будь ласка, включіть якомога детальніші інструкції щодо того, як компілювати та запускати ваш код.

Таблиця лідерів

  • n = 24 Андерс Касеорг в іржі (34 секунди)
  • n = 16 від Ourous в чистоті (36 секунд)
  • n = 14 від JRowan у Common Lisp (49 секунд)

Отже, якщо s = 8, то це масив усіх можливих комбінацій 8 і 9, нічого іншого?
JRowan

@JRowan Ні. Ви не рахуєте жодного з тих масивів, які мають той самий набір сум, як і інший масив.
Ануш

Ця частина, яку я трохи плутаю, ми розглянемо лише масиви, де елементами є або задане ціле число 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].
Андерс Касеорг

Відповіді:


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

Це чудово, дякую. Він завершується за n = 25 приблизно за 90 секунд. Але головна проблема полягає в тому, що він використовує 70% моїх 8 Гб оперативної пам’яті.
Ануш

Мене раптом щось занепокоїло. Ви перевіряєте, чи є масиви унікальними щодо всіх інших можливих масивів, чи просто масиви зі значеннями sта s+1в них?
Ануш

@Anush Так, я торгував деяким використанням пам'яті для швидкості. Я рахую масиви, які є унікальними для інших масивів зі значеннями sта s + 1(оскільки ви сказали, що це єдині масиви, які ми розглянемо), хоча це не одразу очевидно, чи змінює це значення.
Андерс Касеорг

1
Я думаю, мені потрібно буде опрацювати це завтра. Масиви 1,1,2,2 та 1,1,1,3 дають сукупність сум 1,2,3,4,5,6. Однак перший не є унікальним серед масивів, що мають лише 1 і 2, тому я трохи розгублений, якщо зараз це має значення.
Ануш

2
@Anush Це має значення: суми [1, 2, 2, 2] є унікальними серед масивів, що мають довжину 1 і 2, але дорівнюють сумам [1, 1, 2, 3].
Андерс Касеорг

2

Звичайний SBCL Lisp, 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якось викликати його ?
Ануш

1
Я використовую emacs та слизь, але ви можете помістити його у файл скажімо test.lisp та в підказку sbcl у виклику вашого каталогу (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 Хм, я знаю, що перевірив. Я побачу, чи я змінив щось між цим та опублікованим, дайте мені кілька годин, і я можу це зробити на перерві.
Οurous

@Anush Чому ти надаєш s? У запитанні, яке ви заявляєте " Для даного n , ваш код повинен вивести відповідь на всі значення s від 1 до 9."
Οurous

1
Я думаю, що це те, що ви називаєте замороженням мозку з мого боку :) Я зараз приберу ваш код.
Ануш
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.