নির্বিচারে এলোমেলো (গতির সংস্করণ)


10

পূর্ণসংখ্যা দেওয়া হয়েছে n, nপরিসীমাটিতে 1..n^2( এলোমেলো ) এলোমেলো অনন্য পূর্ণসংখ্যার একটি সেট গণনা করুন যাতে সেটটির যোগফল সমান হয়n^2

এলোমেলো, এই ক্ষেত্রে, বৈধ আউটপুটগুলির মধ্যে সমানভাবে এলোমেলো অর্থ । প্রদত্ত প্রতিটি বৈধ আউটপুটে nঅবশ্যই উত্পন্ন হওয়ার অভিন্ন সুযোগ থাকতে হবে।

উদাহরণস্বরূপ, n=3একটি 1/3 সুযোগ outputting প্রতিটি থাকা উচিত 6, 1, 2, 3, 5, 1অথবা 4, 3, 2। যেহেতু এটি একটি সেট, অর্ডার অপ্রাসঙ্গিক, 4, 3, 2এর অনুরূপ3, 2, 4

স্কোরিং

বিজয়ী হ'ল এমন একটি প্রোগ্রাম যা 60০ nসেকেন্ডের চেয়ে কমের মধ্যে সর্বোচ্চ গণনা করতে পারে ।
দ্রষ্টব্য: সম্ভাব্য আংশিক হার্ডকোডিং প্রতিরোধ করতে, সমস্ত এন্ট্রি 4000 বাইটের নিচে থাকতে হবে

পরীক্ষামূলক

সমস্ত কোডটি আমার স্থানীয় উইন্ডোজ 10 মেশিনে চালিত হবে (আপনি জিপিইউর অপব্যবহার করতে চান তবে রেজার ব্লেড 15, 16 গিগাবাইট র‌্যাম, ইন্টেল আই 7-8750H 6 কোর, 4.1GHz, জিটিএক্স 1060) তাই আপনার কোডটি চালানোর জন্য বিস্তারিত নির্দেশাবলী সরবরাহ করুন আমার যন্ত্র
অনুরোধের ভিত্তিতে, ডাব্লুএসএলে ডেবিয়ানের মাধ্যমে বা একটি জুবুন্টু ভার্চুয়াল মেশিনে (উপরের মতো একই মেশিনে উভয়) এন্ট্রিগুলি চালানো যেতে পারে

জমা দেওয়ার ধারাবাহিকতায় 50 বার সঞ্চালিত হবে, চূড়ান্ত স্কোর সমস্ত 50 ফলাফলের গড় হবে।



হার্ডকোডিংটি কি 4000 বাইটের নিচে থাকলে কিছুটা অনুমোদিত?
কুইন্টেক

@ কুইন্টেক না, হার্ডকোডিং একটি স্ট্যান্ডার্ড লুফোল, সুতরাং এটি ডিফল্টরূপে নিষিদ্ধ। কঠিন জিনিসটি হার্ডকোডিংকে একটি অযৌক্তিক মানদণ্ড হিসাবেও বিবেচনা করা হয়, সুতরাং লুফোলটি যেটি অস্বীকার করে তার বাইরে আমি আনুষ্ঠানিকভাবে "কোনও হার্ডকোডিং" বলতে পারি না। সুতরাং বাইট সীমা। অন্য কথায়: দয়া করে হার্ডকোড করবেন না
স্কিডেদেব

1
বেশিরভাগ সাবমিশনগুলি প্রত্যাখ্যান পদ্ধতি ব্যবহার করবে এবং এভাবে চলমান সময় এলোমেলো হবে এবং এর বৃহত পরিবর্তনশীলতা থাকবে। এটি সময়কে কঠিন করে তোলে
লুইস মেন্ডো

2
ওহ, আমি ভুলে গিয়েছিলাম - কারণ কিছু সমাধান দ্রুত মানের জন্য নিম্ন-মানের আরএনজি ব্যবহার করার সিদ্ধান্ত নিতে পারে, তাই ব্ল্যাক বক্সের রুটিন সরবরাহ করা প্রয়োজন হতে পারে যা n নেয় এবং এলোমেলো সংখ্যা তৈরি করে (1..n), এবং সমস্তকে জোর করে এটি ব্যবহার করার সমাধান।
ব্যবহারকারী 202729

উত্তর:


6

মরিচা , n ≈ 1400

কীভাবে চালাবেন

দিয়ে তৈরি করুন cargo build --release, এবং সাথে চালান target/release/arbitrary-randomness n

এই প্রোগ্রামটি প্রচুর মেমরির সাথে দ্রুত চলে (যতক্ষণ না এটি অদলবদল হয় না, অবশ্যই)। MAX_BYTESবর্তমানে 8 জিবিবিতে সেট করা ধ্রুবকটি সম্পাদনা করে আপনি এর মেমরির ব্যবহার সামঞ্জস্য করতে পারেন ।

কিভাবে এটা কাজ করে

সেটটি বাইনারি সিদ্ধান্তগুলির ক্রমানুসারে নির্মিত হয় (প্রতিটি সংখ্যা সেটের অভ্যন্তরে বা বাইরে হয়), যার প্রতিটি সম্ভাব্য সংমিশ্রণে গতিশীল প্রোগ্রামিং ব্যবহার করে প্রতিটি পছন্দ অনুসারে গঠনযোগ্য সংখ্যার গণনা করা হয়।

এই দ্বিপদী বিভাজন কৌশলটির একটি সংস্করণ ব্যবহার করে বৃহত এন এর জন্য মেমরির ব্যবহার হ্রাস করা হয় ।

Cargo.toml

[package]
name = "arbitrary-randomness"
version = "0.1.0"
authors = ["Anders Kaseorg <andersk@mit.edu>"]

[dependencies]
rand = "0.6"

src/main.rs

extern crate rand;

use rand::prelude::*;
use std::env;
use std::f64;
use std::mem;

const MAX_BYTES: usize = 8 << 30; // 8 gibibytes

fn ln_add_exp(a: f64, b: f64) -> f64 {
    if a > b {
        (b - a).exp().ln_1p() + a
    } else {
        (a - b).exp().ln_1p() + b
    }
}

fn split(steps: usize, memory: usize) -> usize {
    if steps == 1 {
        return 0;
    }
    let mut u0 = 0;
    let mut n0 = f64::INFINITY;
    let mut u1 = steps;
    let mut n1 = -f64::INFINITY;
    while u1 - u0 > 1 {
        let u = (u0 + u1) / 2;
        let k = (memory * steps) as f64 / u as f64;
        let n = (0..memory)
            .map(|i| (k - i as f64) / (i as f64 + 1.))
            .product();
        if n > steps as f64 {
            u0 = u;
            n0 = n;
        } else {
            u1 = u;
            n1 = n;
        }
    }
    if n0 - (steps as f64) <= steps as f64 - n1 {
        u0
    } else {
        u1
    }
}

fn gen(n: usize, rng: &mut impl Rng) -> Vec<usize> {
    let s = n * n.wrapping_sub(1) / 2;
    let width = n.min(MAX_BYTES / ((s + 1) * mem::size_of::<f64>()));
    let ix = |m: usize, k: usize| m + k * (s + 1);
    let mut ln_count = vec![-f64::INFINITY; ix(0, width)];
    let mut checkpoints = Vec::with_capacity(width);
    let mut a = Vec::with_capacity(n);
    let mut m = s;
    let mut x = 1;

    for k in (1..=n).rev() {
        let i = loop {
            let i = checkpoints.len();
            let k0 = *checkpoints.last().unwrap_or(&0);
            if k0 == k {
                checkpoints.pop();
                break i - 1;
            }
            if i == 0 {
                ln_count[ix(0, i)] = 0.;
                for m in 1..=s {
                    ln_count[ix(m, i)] = -f64::INFINITY;
                }
            } else {
                for m in 0..=s {
                    ln_count[ix(m, i)] = ln_count[ix(m, i - 1)];
                }
            }
            let k1 = k - split(k - k0, width - 1 - i);
            for step in k0 + 1..=k1 {
                for m in step..=s {
                    ln_count[ix(m, i)] = ln_add_exp(ln_count[ix(m - step, i)], ln_count[ix(m, i)]);
                }
            }
            if k1 == k {
                break i;
            }
            checkpoints.push(k1);
        };

        while m >= k && rng.gen_bool((ln_count[ix(m - k, i)] - ln_count[ix(m, i)]).exp()) {
            m -= k;
            x += 1;
        }
        a.push(x);
        x += 1;
    }
    a
}

fn main() {
    if let [_, n] = &env::args().collect::<Vec<_>>()[..] {
        let n = n.parse().unwrap();
        let mut rng = StdRng::from_entropy();
        println!("{:?}", gen(n, &mut rng));
    } else {
        panic!("expected one argument");
    }
}

এটি অনলাইন চেষ্টা করুন!

(দ্রষ্টব্য: টিআইও সংস্করণে কয়েকটি পরিবর্তন রয়েছে First প্রথমত, মেমরির সীমাটি 1 জিবিবিতে কমানো হয় Second দ্বিতীয়ত, যেহেতু টিআইও আপনাকে একটি লিখতে দেয় না Cargo.tomlএবং যেমন বাইরের ক্রেটের উপর নির্ভর করতে দেয় না rand, আমি পরিবর্তে drand48সি লাইব্রেরিটি থেকে সিলেক্ট্রাইনটি ব্যবহার করে টেনে আনি এফএফআই। আমি এটি বীজ করার জন্য মাথা ঘামাইনি, তাই টিআইও সংস্করণ প্রতিটি রানেই একই ফলাফল উত্পন্ন করবে O


যেহেতু ভাসমান পয়েন্ট ফর্ম্যাটটি সীমাবদ্ধ, ln_add_expচূড়ান্ত পার্থক্যটি 15 ডলার বা তার চেয়ে বড় কিনা তা যাচাই করেই অনুকূলিতকরণ করা সম্ভব, যদি এর মধ্যে প্রচুর সংযোজন ঘটে তবে দ্রুত হতে পারে।
ব্যবহারকারী 202729

@ user202729 নাহ, প্রায় সমস্ত ln_add_expকলের সাথে তুলনামূলক ইনপুট যুক্ত হয়।
অ্যান্ডারস কাসরর্গ

3

TIO এ জাভা 7+, n = 50 ~ 30 সেকেন্ডে

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.Random;
class Main{
  public static void main(String[] a){

    int n=50;

    Random randomGenerator = new Random();
    int i = n+1;
    int squaredN = n*n;
    int[]randomIntegers = new int[i];
    randomIntegers[n] = squaredN;
    while(true){
      for(i=n; i-->1; ){
        randomIntegers[i] = randomGenerator.nextInt(squaredN);
      }
      Set<Integer> result = new HashSet<>();
      Arrays.sort(randomIntegers);
      for(i=n; i-->0; ){
        result.add(randomIntegers[i+1] - randomIntegers[i]);
      }
      if(!result.contains(0) && result.size()==n){
        System.out.println(result);
        return;
      }
    }
  }
}

এই চ্যালেঞ্জের কোড-গল্ফ সংস্করণের জন্য আমার জবাবের অবিস্মরণীয় সংস্করণ আপাতত কেবলমাত্র একটি ছোটখাটো পরিবর্তন: এটি পরিসরে পূর্ণসংখ্যার java.util.Random#nextInt(limit)পরিবর্তে ব্যবহৃত হয় , কারণ এটি প্রায় দ্বিগুণ দ্রুত(int)(Math.random()*limit)[0, n)

এটি অনলাইনে চেষ্টা করুন।

ব্যাখ্যা:

পদ্ধতির ব্যবহার:

কোডটি দুটি ভাগে বিভক্ত:

  1. nযোগফলের পূর্ণসংখ্যার পরিমাণের তালিকা তৈরি করে n squared
  2. তারপরে এটি যাচাই করে যে সমস্ত মানগুলি অনন্য এবং কোনওটি শূন্য নয় এবং যদি এটি মিথ্যা হয় তবে এটি ফলাফল না হওয়া পর্যন্ত ধুয়ে ফেলা এবং পুনরাবৃত্তি করবে।

পদক্ষেপ 1 নিম্নলিখিত উপ-পদক্ষেপের সাহায্যে সম্পন্ন করা হয়েছে:

1) n-1পরিসীমাটিতে এলোমেলো সংখ্যার পরিমাণের একটি অ্যারে তৈরি করুন [0, n squared)। এবং Add 0এবং n squaredএই তালিকায়। এটি O(n+1)পারফরম্যান্সে সম্পন্ন হয় ।
2) তারপরে এটি বিল্টিনের সাথে অ্যারে বাছাই করবে, ডক্সে যেমন বলা হয়েছে তেমনটি পারফরম্যান্সে java.util.Arrays.sort(int[])সম্পন্ন হবে O(n*log(n)):

ইনটসের নির্দিষ্ট অ্যারেটিকে আরোহণের সংখ্যার ক্রমে সাজান। বাছাই করা অ্যালগরিদমটি একটি সুরযুক্ত কুইকোর্ট, যা জন এল। বেন্টলি এবং এম। ডগলাস ম্যাকল্রয়ের "ইঞ্জিনিয়ারিং এ একটি সাজানো ফাংশন", সফ্টওয়্যার-অনুশীলন এবং অভিজ্ঞতা, খণ্ড। 23 (11) পি 1249-1265 (নভেম্বর 1993)। এই অ্যালগরিদম অনেক ডেটা সেটগুলিতে এন * লগ (এন) পারফরম্যান্স সরবরাহ করে যা অন্যান্য কোকোর্টগুলি চতুষ্পদ পারফরম্যান্সে অবনমিত করে।

3) প্রতিটি জুটির মধ্যে পার্থক্য গণনা করুন। পার্থক্যের এই ফলস্বরূপ তালিকায় nযোগফলগুলি যোগ হবে n squared। এটি O(n)পারফরম্যান্সে সম্পন্ন হয় ।

এখানে একটি উদাহরণ:

// n = 4, nSquared = 16

// n-1 amount of random integers in the range [0, nSquared):
[11, 2, 5]

// Add 0 and nSquared to it, and sort:
[0, 2, 5, 11, 16]

// Calculate differences:
[2, 3, 6, 5]

// The sum of these differences will always be equal to nSquared
sum([2, 3, 6, 5]) = 16

সুতরাং উপরোক্ত এই তিনটি পদক্ষেপটি পারফরম্যান্সের জন্য বেশ ভাল, দ্বিতীয় ধাপ এবং সম্পূর্ণ জিনিসটির লুপের বিপরীতে যা একটি মৌলিক জন্তু-শক্তি। পদক্ষেপ 2 এই উপ-পদক্ষেপে বিভক্ত:

1) পার্থক্য তালিকা ইতিমধ্যে একটি এ সংরক্ষণ করা হয় java.util.Set। এই সেটটির আকার সমান কিনা তা এটি পরীক্ষা করবে n। যদি এটি হয় তবে এর অর্থ আমাদের উত্পন্ন সমস্ত এলোমেলো মানগুলি অনন্য unique
2) এবং এটি চেক করবে যে এটা কোন ধারণ করে 0যেহেতু চ্যালেঞ্জ সীমার মধ্যে র্যান্ডম মানের জন্য জিজ্ঞেস করল, সেটে [1, X], যেখানে Xহয় n squaredমাইনাস এর সমষ্টি [1, ..., n-1]হিসাবে বলেছেন, @Skidsdev নিচে মন্তব্যে।

উপরের দুটি বিকল্পের মধ্যে যদি (সমস্ত মানগুলি অনন্য নয়, বা একটি শূন্য উপস্থিত থাকে) তবে এটি একটি নতুন অ্যারে তৈরি করবে এবং পদক্ষেপ 1 এ পুনরায় সেট করে আবার সেট করুন This এটি আমাদের ফলাফল না হওয়া পর্যন্ত অব্যাহত থাকবে। এ কারণে সময়টি কিছুটা আলাদা হতে পারে। আমি এটি টিআইওতে একবার 3 সেকেন্ডের মধ্যে শেষ করতে দেখেছি n=50, তবে একবারে 55 সেকেন্ডেও n=50

অভিন্নতার প্রমাণ:

কীভাবে এটি সম্পূর্ণ সৎ হতে প্রমাণ করা যায় তা সম্পর্কে আমি পুরোপুরি নিশ্চিত নই। java.util.Random#nextIntযেমন ডক্স বর্ণনা করা হয়েছে, নিশ্চিত অভিন্ন হল:

পরবর্তী সিউডোরেন্ডমটি প্রদান করে, intএই এলোমেলো নম্বর জেনারেটরের ক্রম থেকে সমানভাবে বিতরণকৃত মান। এর সাধারণ চুক্তিটি nextIntহ'ল এক intমান সিউডোর্যান্ডোমিলিকভাবে উত্পন্ন এবং ফিরে আসে। সমস্ত 2 32 সম্ভাব্য intমানগুলি সমান সম্ভাব্যতার সাথে উত্পাদিত হয়।

এগুলি (সাজানো) এলোমেলো মানগুলির মধ্যে পার্থক্যগুলি অবশ্যই অভিন্ন নয়, তবে পুরো সেটগুলি অভিন্ন। আবার, এই গাণিতিকভাবে কীভাবে প্রমাণ করবেন তা আমি নিশ্চিত নই, তবে এখানে একটি স্ক্রিপ্ট রয়েছে যা একটি কাউন্টার সহ মানচিত্রে 10,000উত্পন্ন সেটগুলি (জন্য n=10) স্থাপন করবে , যেখানে বেশিরভাগ সেট অনন্য; কিছু দু'বার পুনরাবৃত্তি; এবং সর্বাধিক পুনরাবৃত্তি ঘটনাটি সাধারণত সীমার মধ্যে থাকে [4,8]

সংস্থাপনের নির্দেশনা:

জাভা যেহেতু জাভা কোড তৈরি এবং চালনা করতে পারে সে সম্পর্কে প্রচুর তথ্য সহ একটি সুপরিচিত ভাষা, সুতরাং আমি এটি সংক্ষেপে রাখব।
আমার কোডে ব্যবহৃত সমস্ত সরঞ্জাম জাভা 7 এ উপলব্ধ (সম্ভবত ইতিমধ্যে জাভা 5 বা 6 তেও রয়েছে, তবে আসুন মাত্র 7 ব্যবহার করুন)। আমি নিশ্চিত যে জাভা 7 যদিও ইতিমধ্যে সংরক্ষণাগারভুক্ত হয়েছে, তাই আমি আমার কোড চালানোর জন্য জাভা 8 ডাউনলোড করার পরামর্শ দেব।

উন্নতি সম্পর্কিত চিন্তাভাবনা:

আমি শূন্যগুলির জন্য চেকের জন্য একটি উন্নতি সন্ধান করতে চাই এবং সমস্ত মান অনন্য are আমি 0আগে যাচাই করতে পারি, এটি নিশ্চিত করে যে আমরা অ্যারেতে যোগ করেছি এলোমেলো মান এটি ইতিমধ্যে নেই, তবে এর অর্থ কয়েকটি জিনিস থাকবে: অ্যারেটি এমন একটি হওয়া উচিত ArrayListযাতে আমরা বিল্টিন পদ্ধতিটি ব্যবহার করতে পারি .contains; আমরা তালিকায় নেই এমন একটি এলোমেলো মান খুঁজে পাওয়া পর্যন্ত অবধি লুপ যুক্ত করা উচিত। যেহেতু এখন শূন্যের জন্য পরীক্ষা করা .contains(0)সেট (যা শুধুমাত্র একবার যাচাই করা হয়েছে) দিয়ে সম্পন্ন .containsকরা হয়েছে, সুতরাং তালিকার সাথে লুপ যোগ করার তুলনায় কর্মক্ষেত্রের পক্ষে সেই পর্যায়ে এটি পরীক্ষা করা আরও ভাল যা কমপক্ষে nবার চেক করা হবে , তবে সম্ভবত আরও।

স্বতন্ত্রতা যাচাইয়ের জন্য, আমাদের কাছে কেবলমাত্র আমাদের nএলোমেলো পূর্ণসংখ্যাগুলি রয়েছে যা n squaredপ্রোগ্রামের প্রথম ধাপের 1 এর পরে যোগ হয় , তবে কেবলমাত্র তখনই আমরা পরীক্ষা করতে পারি যে সমস্ত অনন্য কিনা whether অ্যারের পরিবর্তে বাছাইযোগ্য তালিকা রাখা এবং এর মধ্যে পার্থক্যগুলি পরীক্ষা করা সম্ভব হতে পারে তবে আমি গুরুতরভাবে সন্দেহ করি যে এটি কেবলমাত্র একটিগুলিতে রাখার চেয়ে কর্মক্ষমতা উন্নত করবে Setএবং সেই সেটের আকারটি nএকবার কিনা তা পরীক্ষা করে দেখুন ।


1
যদি এটি গতিতে সহায়তা করে তবে সেটের কোনও সংখ্যা n^2 - sum(1..n-1)উদাহরণের চেয়ে বড় হতে পারে না n=5সবচেয়ে বড় বৈধ সংখ্যাটির জন্য5^2 - sum(1, 2, 3, 4) == 25 - 10 == 15
স্কিডেদেব

@ স্কিডসদেব ধন্যবাদ, সে সম্পর্কে ভাবেননি। যদিও আমার বর্তমান পদ্ধতির সাথে আমি এটি ব্যবহার করতে পারি না, যেহেতু আমি এলোমেলো-জোড়াগুলির মধ্যে পার্থক্যগুলি পাই, এলোমেলো মানগুলির পরিবর্তে directly তবে এটি সম্ভবত অন্যান্য উত্তরের জন্য কার্যকর হতে পারে।
কেভিন ক্রুইজসেন

1
ফলাফলের আকারের আকারটি এর চেয়ে বেশি কখনও হতে পারে না n, তাই না? 0সেক্ষেত্রে আপনি সেটে যোগ করতে পারেন এবং তারপরে আকারটি (এখন) এর চেয়ে বেশি কিনা তা পরীক্ষা করতে পারেন n। এটি কেবল তখনই ঘটতে পারে যখন পার্থক্যগুলি সমস্ত ননজারো এবং স্বতন্ত্র।
নীল

@ নীল ওহ, এটি বেশ স্মার্ট, এবং আমি অবশ্যই আমার কোড-গল্ফের উত্তরটি গল্ফকে কয়েক বাইট ছাড়িয়ে ব্যবহার করব। যদিও এটি এখানে পারফরম্যান্সের উন্নতি করবে কিনা তা আমি নিশ্চিত নই। HashSet.containsবেশিরভাগ ক্ষেত্রেই এটি ঘনিষ্ঠ O(1)এবং সবচেয়ে খারাপ ক্ষেত্রে এটি O(n)জাভা 7 এ এবং O(log n)জাভা 8+ এ (তারা সংঘর্ষ সনাক্তকরণের সাথে চেইন প্রতিস্থাপনের পরে এটি উন্নত করা হয়েছে)। যদি আমাকে 0চেকের জন্য যুক্তযুক্ত সেটটি ফেরত দেওয়ার অনুমতি দেওয়া হয় তবে পারফরম্যান্সের জন্য এটি কিছুটা ভাল, তবে যদি আমাকে যদি set.remove(0);ভিতরে কল করতে হয় তবে আমি নিশ্চিত যে অভিনয়টি কিছুটা একই।
কেভিন ক্রুইজসেন

ওহ, আমি ভুলে গিয়েছিলাম আপনার পাশাপাশি সেটটিও ফিরিয়ে দেওয়া দরকার ... কিছু মনে করবেন না।
নিল

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.