Đếm các mảng tạo nên các bộ duy nhất


11

Câu hỏi này có một thiết lập tương tự để Tìm một mảng phù hợp với một tập hợp mặc dù khá khác nhau trong các mục tiêu của nó.

Hãy xem xét một mảng Achiều dài n. Mảng chỉ chứa số nguyên dương. Ví dụ A = (1,1,2,2). Hãy để chúng tôi định nghĩa f(A)là tập hợp của tất cả các phân đoạn tiếp giáp không trống của A. Trong trường hợp này f(A) = {1,2,3,4,5,6}. Các bước để sản xuất f(A) như sau:

Các subarrays của A(1), (1), (2), (2), (1,1), (1,2), (2,2), (1,1,2), (1,2,2), (1,1,2,2). Số tiền tương ứng của họ là 1,1,2,2,2,3,4,4,5,6. Do đó, bộ bạn nhận được từ danh sách này là do {1,2,3,4,5,6}.

Chúng tôi gọi một mảng A duy nhất nếu không có mảng nào khác có Bcùng độ dài như vậy f(A) = f(B), ngoại trừ mảng bị Ađảo ngược. Ví dụ, f((1,2,3)) = f((3,2,1)) = {1,2,3,5,6}nhưng không có mảng độ dài 3nào khác tạo ra cùng một tập hợp tổng.

Chúng tôi sẽ chỉ xem xét các mảng trong đó các phần tử là một số nguyên cho trước shoặc s+1. Ví dụ, nếu s=1các mảng sẽ chỉ chứa 12.

Bài tập

Nhiệm vụ, cho một nvà nhất định slà đếm số lượng các mảng duy nhất có độ dài đó. Bạn có thể cho rằng đó slà giữa 19.

Bạn không nên đếm ngược lại của một mảng cũng như chính mảng đó.

Ví dụ

s = 1, câu trả lời là luôn n+1.

s = 2, các câu trả lời đếm từ n = 1lên là:

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

s = 8, các câu trả lời đếm từ n = 1lên là:

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

Ghi bàn

Đối với một nmã nhất định , mã của bạn sẽ đưa ra câu trả lời cho tất cả các giá trị stừ 1đến 9. Điểm của bạn là giá trị cao nhất nmà điều này hoàn thành trong một phút.

Kiểm tra

Tôi sẽ cần chạy mã của bạn trên máy ubfox của mình, vì vậy vui lòng bao gồm các hướng dẫn chi tiết nhất có thể về cách biên dịch và chạy mã của bạn.

Bảng xếp hạng

  • n = 24 của Anders Kaseorg ở Rust (34 giây)
  • n = 16 bởi Ourous in Clean (36 giây)
  • n = 14 của JRowan trong Lisp chung (49 giây)

Vậy nếu s = 8 thì đó là một mảng gồm tất cả các kết hợp có thể có của 8 và 9, không có gì khác?
JRowan

@JRowan Không. Bạn không đếm bất kỳ mảng nào có cùng một bộ tổng như một số mảng khác.
Anush

Phần này tôi hơi bối rối về Chúng tôi sẽ chỉ xem xét các mảng trong đó các phần tử là một số nguyên s hoặc s + 1 đã cho. Ví dụ: nếu s = 1 thì các mảng sẽ chỉ chứa 1 và 2. Vậy nếu n là 2 và s là 3 thì các mảng cần kiểm tra là gì?
JRowan

những gì về [3,3] và tôi hiện đang loại bỏ mặt trái của danh sách, ví dụ. [3,4] -> [4,3]
JRowan

2
@RosLuP Thứ nhất, bạn muốn đăng câu hỏi đó lên câu hỏi khác và thứ hai, [3, 5, 4] là một tập hợp con nhưng không phải là một phân nhóm của [3, 5, 1, 4].
Anders Kaseorg

Câu trả lời:


5

Rust , n ≈ 24

Yêu cầu Rust hàng đêm cho các reverse_bitstính năng thuận tiện . Biên dịch với rustc -O unique.rsvà chạy với (ví dụ) ./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.
}

Điều này là rất tốt, cảm ơn bạn. Nó hoàn thành trong n = 25 trong khoảng 90 giây. Nhưng vấn đề chính là nó sử dụng 70% RAM 8GB của tôi.
Anush

Tôi đã đột nhiên lo lắng về một cái gì đó. Bạn đang kiểm tra xem các mảng là duy nhất đối với tất cả các mảng có thể khác hay chỉ là các mảng có giá trị ss+1trong đó?
Anush

@Anush Có, tôi đã trao đổi một số sử dụng bộ nhớ cho tốc độ. Tôi đang đếm các mảng là các mảng duy nhất khác với các giá trị ss + 1(vì bạn nói đó là các mảng duy nhất chúng tôi sẽ xem xét), mặc dù điều đó không rõ ràng ngay lập tức liệu điều đó có làm nên sự khác biệt hay không.
Anders Kaseorg

1
Tôi nghĩ rằng tôi sẽ cần phải làm việc này vào ngày mai. Các mảng 1,1,2,2 và 1,1,1,3 đều cho tập hợp các khoản tiền 1,2,3,4,5,6. Tuy nhiên, cái trước đây không phải là duy nhất trong số các mảng chỉ có 1 và 2 vì vậy tôi hơi bối rối nếu bây giờ nó tạo ra sự khác biệt.
Anush

2
@Anush Điều này làm nên sự khác biệt: các tổng của [1, 2, 2, 2] là duy nhất trong số các mảng có 1 và 2 chiều dài 4, nhưng bằng tổng của [1, 1, 2, 3].
Anders Kaseorg

2

Lisp SBCL thường gặp, N = 14

chức năng gọi (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)))))

đây là thời gian chạy

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)

Làm thế nào để tôi chạy cái này? Tôi có sao chép mã của bạn vào một tệp và gọi nó từ một sbclcách nào đó không?
Anush

1
Tôi sử dụng emacs và slime nhưng bạn có thể đặt nó trong một tập tin nói test.lisp và trong lời nhắc sbcl tại cuộc gọi thư mục của bạn (tải "test.lisp") và sau đó gọi hàm làm thế nào tôi có nó ở dưới cùng
JRowan

2

Dọn dẹp

Chắc chắn không phải là cách tiếp cận hiệu quả nhất, nhưng tôi quan tâm đến việc xem bộ lọc theo giá trị ngây thơ hoạt động tốt như thế nào.

Điều đó nói rằng, vẫn còn một chút cải tiến được thực hiện bằng phương pháp này.

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

Đặt trong một tệp có tên main.icl, hoặc thay đổi dòng trên cùng module <your_file_name_here>.

Biên dịch với clm -h 1500m -s 50m -fusion -t -IL Dynamics -IL StdEnv -IL Platform main.

Bạn có thể lấy phiên bản TIO (và bản thân tôi) sử dụng từ liên kết trong tiêu đề hoặc một phiên bản gần đây hơn từ đây .


Tôi không nghĩ mã này cho đầu ra đúng. Tôi đã thử nó với s = 8 và nó cho [9,86,126,130,130,130,130,130,130]
Anush

@Anush hmm Tôi biết tôi đã thử nó. Tôi sẽ xem liệu tôi có thay đổi bất cứ điều gì giữa cái đó và cái được đăng không, cho tôi vài giờ và tôi có thể làm điều đó vào giờ nghỉ của mình.
urous

@Anush Tại sao bạn cung cấp s? Trong câu hỏi bạn nêu " Đối với n cho trước , mã của bạn sẽ xuất câu trả lời cho tất cả các giá trị của s từ 1 đến 9."
Οurous

1
Tôi nghĩ rằng đó là những gì bạn gọi là đóng băng não của tôi :) Tôi sẽ thời gian mã của bạn bây giờ.
Anush
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.