เข้าถึงหมายเลขนำโชคของคน ๆ หนึ่ง


21

นักกอล์ฟรหัสใหม่โจเพิ่งลงทะเบียนกับเว็บไซต์ เขามี 1 ชื่อเสียง แต่มุ่งมั่นที่จะเข้าถึงผู้โชคดีทุกคนในชื่อเสียง โจเชื่อในพลังที่สูงขึ้นซึ่งจะช่วยให้เขาบรรลุเป้าหมายด้วยการกระทำน้อยที่สุด (ของเขาหรือคนอื่น ๆ ) ในฐานะผู้ใช้ใหม่เขาเชื่อว่าชื่อเสียงในทางลบเป็นไปได้

คุณควรเขียนโปรแกรมหรือฟังก์ชั่นที่ช่วยให้โจคำนวณจำนวนการกระทำที่เขาคาดหวัง

รายละเอียด

  • การดำเนินการสามารถเปลี่ยนชื่อเสียงตามจำนวนต่อไปนี้ (การดำเนินการทั้งหมดมีอยู่ในทุกขั้นตอนโดยไม่คำนึงถึงกฎ stackexchange):

    answer accepted:     +15
    answer voted up:     +10
    question voted up:    +5
    accepts answer:       +2
    votes down an answer: −1
    question voted down:  −2
    
  • การเปลี่ยนแปลงชื่อเสียงอื่น ๆ ไม่ได้รับการใส่ใจ

  • หมายเลขนำโชคสามารถเป็นค่าลบและสามารถติดต่อได้ในลำดับใดก็ได้
  • โซลูชันของคุณต้องแก้ไขกรณีทดสอบตัวอย่างใด ๆ ในเวลาไม่กี่นาทีบนคอมพิวเตอร์ของฉัน (ฉันจะทดสอบเฉพาะกรณีที่ปิดฉันมีพีซีต่ำกว่าค่าเฉลี่ย)

อินพุต

  • ตัวเลขนำโชคของ Joe เป็นรายการจำนวนเต็มในรูปแบบทั่วไปของภาษาของคุณ

เอาท์พุต

  • จำนวนการดำเนินการขั้นต่ำที่ต้องการเป็นจำนวนเต็มเดียว
  • เอาต์พุตสามารถพิมพ์ไปที่ stdout หรือส่งคืนเป็นจำนวนเต็ม

ตัวอย่าง

อินพุต => เอาท์พุท (สถานะภาพตัวอย่าง)

1                     => 0  (1)
3 2 1                 => 2  (1 -> 3 -> 2)
2 10 50               => 7  (1 -> 3 -> 2 -> 12 -> 10 -> 25 -> 40 -> 50)
10 11 15              => 3  (1 -> 11 -> 10 -> 15)
42 -5                 => 7  (1 -> -1 -> -3 -> -5 -> 10 -> 25 -> 40 -> 42)
-10                   => 6  (1 -> -1 -> -3 -> -5 -> -7 -> -9 -> -10)
15 -65                => 39
7 2015 25 99          => 142
-99 576 42 1111 12345 => 885

นี่คือรหัสกอล์ฟเพื่อให้รายการที่สั้นที่สุดชนะ

คำตอบ:


1

C # - 501 ไบต์

อัปเดต 551 -> 501 ไบต์

namespace System.Linq{class A {static void Main(){var i = c(new int[]{10,11,15});Console.WriteLine(i);Console.ReadLine();}private static int c(int[] a){var o=a.OrderBy(x => x).ToArray();int d=1,count=0;for(var i=0;i<a.Length;i++){if(o[i]==d)i++;int c=o[i],b=o.Length>=i+2?o[i+1]-o[i]:3;if(b<=2){i++;c=o[i];}while(d!=c){if(d>c){var e=d-c;if(e>1)d-=2;else d-=1;}else if(c>d){var e=c-d+2;if(e>14)d+=15;else if(e>9)d+=10;else if(e>4)d+=5;else if(e>2)d+=2;}count++;}if(b<=2){d-=b;count++;}}return count;}}}

รหัสไม่ได้รับการตอบ

namespace System.Linq {
    class Program {
        static void Main(){
            var i = CalculateNumbers(new int[]{10,11,15});
            Console.WriteLine(i);
            Console.ReadLine();
        }
        private static int CalculateNumbers(int[] numbers){
            var ordered = numbers.OrderBy(x => x).ToArray();
            int cur = 1, count = 0;
            for (var i = 0; i < numbers.Length; i++){
                if (ordered[i] == cur) i++;
                int val = ordered[i], next = ordered.Length >= i+2 ? ordered[i + 1] - ordered[i] : 3;
                if (next <= 2){
                    i++;
                    val = ordered[i];
                }
                while (cur != val){
                    if (cur > val){
                        var dif = cur - val;
                        if (dif > 1)
                            cur -= 2;
                        else
                            cur -= 1;
                    } else if (val > cur){
                        var dif = val - cur + 2;
                        if (dif > 14)
                            cur += 15;
                        else if (dif > 9)
                            cur += 10;
                        else if (dif > 4)
                            cur += 5;
                        else if (dif > 2)
                            cur += 2;
                    }
                    count++;
                }
                if (next <= 2){
                    cur -= next;
                    count++;
                }
            }
            return count;
        }
    }
}

16

สนิม929 923 ตัวอักษร

use std::io;use std::str::FromStr;static C:&'static [i32]=&[-2,-1,2,5,10,15];fn main(){let mut z=String::new();io::stdin().read_line(&mut z).unwrap();let n=(&z.trim()[..]).split(' ').map(|e|i32::from_str(e).unwrap()).collect::<Vec<i32>>();let l=*n.iter().min().unwrap();let x=n.iter().max().unwrap()-if l>1{1}else{l};let s=g(x as usize);println!("{}",p(1,n,&s));}fn g(x:usize)->Vec<i32>{let mut s=vec![std::i32::MAX-9;x];for c in C{if *c>0&&(*c as usize)<=x{s[(*c-1)as usize]=1;}}let mut i=1us;while i<x{let mut k=i+1;for c in C{if(i as i32)+*c<0{continue;}let j=((i as i32)+*c)as usize;if j<x&&s[j]>s[i]+1{s[j]=s[i]+1;if k>j{k=j;}}}i=k;}s}fn p(r:i32,n:Vec<i32>,s:&Vec<i32>)->i32{if n.len()==1{h(r,n[0],&s)}else{(0..n.len()).map(|i|{let mut m=n.clone();let q=m.remove(i);p(q,m,&s)+h(r,q,&s)}).min().unwrap()}}fn h(a:i32,b:i32,s:&Vec<i32>)->i32{if a==b{0}else if a>b{((a-b)as f32/2f32).ceil()as i32}else{s[(b-a-1)as usize]}}

สนุกมาก!


ความเห็นเกี่ยวกับการดำเนินการ

เห็นได้ชัดว่าฉันไม่ได้มีความสุขกับขนาด แต่สนิมนั้นยอดเยี่ยมมากในการเล่นกอล์ฟ อย่างไรก็ตามการแสดงนั้นยอดเยี่ยมมาก

รหัสแก้ปัญหาแต่ละกรณีการทดสอบอย่างถูกต้องในระยะเวลาอันใกล้ดังนั้นประสิทธิภาพจึงไม่เป็นปัญหา เพื่อความสนุกนี่เป็นกรณีทดสอบที่ยากกว่านี้มาก:

1234567 123456 12345 1234 123 777777 77777 7777 777

ซึ่งคำตอบคือ82317โปรแกรมของฉันสามารถแก้ไขบนแล็ปท็อปของฉัน (ประสิทธิภาพปานกลาง) ใน1.66 วินาที (!) แม้จะใช้อัลกอริธึมเส้นทาง Hamiltonian ที่โหดร้ายแบบเรียกซ้ำ

ข้อสังเกต

  • ก่อนอื่นเราควรสร้างกราฟถ่วงน้ำหนักที่มีการปรับเปลี่ยนโดยโหนดต่างๆเป็นหมายเลข "โชคดี" และน้ำหนักเป็นจำนวนการเปลี่ยนแปลงที่ต้องได้รับจากระดับชื่อเสียงหนึ่งไปสู่อีกระดับ แต่ละคู่ของโหนดจะต้องเชื่อมต่อด้วยสองขอบเนื่องจากการขึ้นไปนั้นไม่เหมือนกับการลงในค่าชื่อเสียง (คุณสามารถรับ +10 ตัวอย่างเช่น แต่ไม่ใช่ -10)

  • ตอนนี้เราต้องหาวิธีหาจำนวนการเปลี่ยนแปลงขั้นต่ำจากค่าตัวแทนหนึ่งไปสู่อีกค่า

    • สำหรับการเดินทางจากมูลค่าที่สูงกว่าเป็นค่าที่ต่ำกว่ามันง่าย: เพียงแค่ใช้เวลาceil((a - b) / 2)ที่aเป็นค่าที่สูงขึ้นและbเป็นค่าที่ต่ำกว่า ตัวเลือกเชิงตรรกะเพียงอย่างเดียวของเราคือการใช้ -2 ให้มากที่สุดจากนั้นเลือก -1 เพียงครั้งเดียวหากจำเป็น

    • ค่าต่ำถึงสูงนั้นซับซ้อนกว่าเล็กน้อยเนื่องจากการใช้ค่าสูงสุดที่เป็นไปได้นั้นอาจไม่เหมาะสมเสมอไป (เช่นสำหรับ 0 ถึง 9 ทางออกที่ดีที่สุดคือ +10 -1) อย่างไรก็ตามนี่เป็นปัญหาการเขียนโปรแกรมแบบไดนามิกของตำราเรียนและ DP แบบง่ายก็เพียงพอที่จะแก้ปัญหาได้

  • เมื่อเราคำนวณการเปลี่ยนแปลงขั้นต่ำจากแต่ละหมายเลขเป็นตัวเลขอื่น ๆ แล้วเราจะเหลือส่วนต่างของ TSP เล็กน้อย (ปัญหาพนักงานขายเดินทาง) โชคดีที่มีจำนวนโหนดน้อยมาก (สูงสุด 5 ในกรณีทดสอบที่ยากที่สุด) ที่แรงเดรัจฉานก็เพียงพอสำหรับขั้นตอนนี้

รหัสที่ไม่ได้รับการตอบรับ (มีการแสดงความคิดเห็นอย่างมาก)

use std::io;
use std::str::FromStr;

// all possible rep changes
static CHANGES: &'static [i32] = &[-2, -1, 2, 5, 10, 15];

fn main() {
    // read line of input, convert to i32 vec
    let mut input = String::new();
    io::stdin().read_line(&mut input).unwrap();
    let nums = (&input.trim()[..]).split(' ').map(|x| i32::from_str(x).unwrap())
        .collect::<Vec<i32>>();

    // we only need to generate as many additive solutions as max(nums) - min(nums)
    // but if one of our targets isn't 1, this will return a too-low value.
    // fortunately, this is easy to fix as a little hack
    let min = *nums.iter().min().unwrap();
    let count = nums.iter().max().unwrap() - if min > 1 { 1 } else { min };
    let solutions = generate_solutions(count as usize);

    // bruteforce!
    println!("{}", shortest_path(1, nums, &solutions));
}

fn generate_solutions(count: usize) -> Vec<i32> {
    let mut solutions = vec![std::i32::MAX - 9; count];

    // base cases
    for c in CHANGES {
        if *c > 0 && (*c as usize) <= count {
            solutions[(*c-1) as usize] = 1;
        }
    }

    // dynamic programming! \o/
    // ok so here's how the algorithm works.
    // we go through the array from start to finish, and update the array
    //   elements at i-2, i-1, i+2, i+5, ... if solutions[i]+1 is less than
    //   (the corresponding index to update)'s current value
    // however, note that we might also have to update a value at a lower index
    //   than i (-2 and -1)
    // in that case, we will have to go back that many spaces so we can be sure
    //   to update *everything*.
    // so for simplicity, we just set the new index to be the lowest changed
    //   value (and increment it if there were none changed).
    let mut i = 1us;  // (the minimum positive value in CHANGES) - 1 (ugly hardcoding)
    while i < count {
        let mut i2 = i+1;
        // update all rep-values reachable in 1 "change" from this rep-value,
        //   by setting them to (this value + 1), IF AND ONLY IF the current
        //   value is less optimal than the new value
        for c in CHANGES {
            if (i as i32) + *c < 0 { continue; }  // negative index = bad
            let idx = ((i as i32) + *c) as usize;  // the index to update
            if idx < count && solutions[idx] > solutions[i]+1 {
                // it's a better solution! :D
                solutions[idx] = solutions[i]+1;
                // if the index from which we'll start updating next is too low,
                //   we need to make sure the thing we just updated is going to,
                //   in turn, update other things from itself (tl;dr: DP)
                if i2 > idx { i2 = idx; }
            }
        }
        i = i2;  // update index (note that i2 is i+1 by default)
    }

    solutions
}

fn shortest_path(rep: i32, nums: Vec<i32>, solutions: &Vec<i32>) -> i32 {
    // mercifully, all the test cases are small enough so as to not require
    //   a full-blown optimized traveling salesman implementation
    // recursive brute force ftw! \o/
    if nums.len() == 1 { count_changes(rep, nums[0], &solutions) }  // base case
    else {
        // try going from 'rep' to each item in 'nums'
        (0..nums.len()).map(|i| {
            // grab the new rep value out of the vec...
            let mut nums2 = nums.clone();
            let new_rep = nums2.remove(i);
            // and map it to the shortest path if we use that value as our next target
            shortest_path(new_rep, nums2, &solutions) + count_changes(rep, new_rep, &solutions)
        }).min().unwrap()  // return the minimum-length path
    }
}

fn count_changes(start: i32, finish: i32, solutions: &Vec<i32>) -> i32 {
    // count the number of changes required to get from 'start' rep to 'finish' rep
    // obvious:
    if start == finish { 0 }
    // fairly intuitive (2f32 is just 2.0):
    else if start > finish { ((start - finish) as f32 / 2f32).ceil() as i32 }
    // use the pregenerated lookup table for these:
    else /* if finish > start */ { solutions[(finish - start - 1) as usize] }
}

1
คำตอบที่ยอดเยี่ยม! ฉันสนใจสนิมและคำอธิบายนั้นมีประโยชน์มากสำหรับการเรียนรู้ <!-- language-all: lang-rust -->และเช่นเดียวกับหัวขึ้นคุณจะได้รับการเน้นไวยากรณ์ด้วย ;)
Alex A.

ฉันกำลังหาทางแก้ปัญหาและเห็นว่าการเปลี่ยนแปลงจำนวนน้อยที่สุดเกี่ยวกับน้ำหนักต่ำถึงสูงสามารถคำนวณได้อย่างง่ายดายใน O (1) โดยใช้ตารางการค้นหาขนาดเล็กมากเช่นในรหัสหลอก C-like floor((a-b)/15)+{0,2,1,2,2,1,3,2,2,2,1,3,2,2,2}[(a-b)%15]นี้ โซลูชันของคุณอาจได้รับประโยชน์จากสิ่งนี้
Fors

2

Pyth - 43 42 ไบต์

ใช้วิธีการเดรัจฉานแรงอย่างสมบูรณ์กับการเรียงสับเปลี่ยนและการรวมกันทั้งหมด ไม่มองกอล์ฟมากขึ้นเพราะจะแปลเป็น Pyth แปล

K5tf.Em.Am}kmhs<dbUdQsm.pk.C[15yKK2_1_2)TZ

นี่ช้ากว่ารุ่นไพ ธ อนเพราะฉันใช้ตัวกรองแทนการวนซ้ำสักครู่ คำอธิบายจะมาเร็ว ๆ นี้ดูรหัส Python

ลองมันนี่เกมออนไลน์

from itertools import*
Q,Z=eval(input()),0
while True:
    if any(map(lambda d:all(map(lambda k:k in map(lambda b:sum(d[:b])+1,range(len(d))),Q)),chain.from_iterable(map(lambda k:permutations(k),combinations_with_replacement([15,10,5,2,-1,-2],Z))))):
        print(Z-1)
        break
    Z+=1

ใช้งานได้กับตัวเล็ก ๆ อย่าปล่อยให้มันทำงานจนเสร็จในตัวใหญ่


ยังไม่ได้อ่านรหัสอย่างถูกต้อง แต่คุณสามารถแทนที่ 10 ด้วยพูดy5เพื่อบันทึกในช่องว่างหรือไม่
Sp3000

@ Sp3000 มันจะช่วยลดช่องว่าง แต่ไม่รวมตัวอักษรใด ๆ แต่ฉันคิดว่าฉันสามารถประหยัดถ่านด้วยการบีบอัดรายการโดยการจัดเก็บK=5
Maltysen

โปรดทราบว่าคำตอบนี้ไม่เป็นไปตามกฎเนื่องจาก "โซลูชันของคุณต้องแก้ไขกรณีทดสอบตัวอย่างใด ๆ ไม่เกินหนึ่งนาที" (อ้างเป็นตัวหนาในส่วนรายละเอียด.)
randomra

0

C ++ - 863 ไบต์ไม่ได้รับพร

สิ่งนี้จะทำงานค่อนข้างเร็วใน ballpark เดียวกับวิธีแก้ปัญหาที่เขียนใน Rust (เร็วกว่าประมาณ 6 เท่าเมื่อคอมไพล์ด้วยการปรับให้เหมาะสมที่สุด) ฉันจะเล่นกอล์ฟช่วงเย็นนี้ (เย็นที่สวีเดนนั่นคือ)

#include <iostream>
#include <vector>
#include <string>
#include <sstream>

const int lookup[] = {0, 2, 1, 2, 2, 1, 3, 2, 2, 2, 1, 3, 2, 2, 2};

int distance(int start, int end) {
    return start > end
        ? (start - end + 1) / 2
        : (end - start) / 15 + lookup[(end - start) % 15];
}

int walk(int current, std::vector<int> points) {
    int min = 0;

    if (points.size() == 0) return 0;

    for (int i = 0; i < points.size(); i++) {
        std::vector<int> new_points = points;
        new_points.erase(new_points.begin() + i);

        int d = distance(current, points[i]) + walk(points[i], new_points);

        min = min && min < d ? min : d;
    }

    return min;
}

int main() {
    std::vector<int> points;

    std::string line;
    std::getline(std::cin, line);

    std::stringstream ss(line);
    int i;

    while (ss >> i)
        points.push_back(i);

    std::cout << walk(1, points) << std::endl;

    return 0;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.