평판이 좋은 사람에게 다가 가다


21

새로운 코드 골퍼 인 Joe가 방금 사이트에 등록했습니다. 그는 평판이 1이지만 평판이 좋은 모든 행운의 숫자에 도달하기로 결정했습니다. Joe는 최소한의 (그 또는 다른) 행동으로 목표를 달성하는 데 도움이되는 더 높은 힘을 믿습니다. 그는 새로운 사용자로서 부정적인 평판이 가능하다고 생각합니다.

Joe가 예상해야하는 조치 수를 계산하는 데 도움이되는 프로그램이나 함수를 작성해야합니다.

세부

  • 조치는 다음 금액으로 평판을 변경할 수 있습니다 (스택 교환 규칙에 관계없이 모든 단계에서 모든 조치를 사용할 수 있음).

    answer accepted:     +15
    answer voted up:     +10
    question voted up:    +5
    accepts answer:       +2
    votes down an answer: −1
    question voted down:  −2
    
  • 다른 특별한 평판 변경은 무시됩니다.

  • 운이 좋은 숫자는 음수 일 수 있으며 어떤 순서로도 도달 할 수 있습니다.
  • 귀하의 솔루션은 내 컴퓨터 에서 1 분 이내에 예제 테스트 사례를 해결해야 합니다 (닫기 사례 만 테스트합니다. 평균 이하의 PC가 있습니다).

입력

  • 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;}}}

Ungolfed 코드

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 초 (!) 에 (중간 성능) 랩톱에서 해결할 수있었습니다 .

관찰

  • 먼저 노드가 각각 "운이 좋은"숫자이고 가중치가 한 평판 수준에서 다른 평판 수준으로 변경되는 데 걸리는 변경 횟수를 기준으로 수정 된 가중치 그래프를 작성해야합니다. 위로 올라가는 것은 평판 값으로 내려가는 것과 같지 않기 때문에 각 노드 쌍은 두 개의 가장자리 로 연결되어야합니다 (예 : +10은 가능하지만 -10은 안 됨).

  • 이제 한 rep 값에서 다른 rep 값으로 최소 변경 량을 찾는 방법을 찾아야합니다.

    • 더 높은 값에서 더 낮은 값으로 이동하려면 간단합니다. 더 높은 값과 더 낮은 값 을 ceil((a - b) / 2)어디에서 가져 가십시오 . 우리의 유일한 논리적 옵션은 가능한 한 -2를 사용하고 필요한 경우 -1을 사용하는 것입니다.ab

    • 가능한 가장 큰 값을 사용하는 것이 항상 최적이 아니기 때문에 (낮은 값에서 높은 값) 조금 더 복잡합니다 (예 : 0에서 9의 경우 최적 솔루션은 + 10-1). 그러나 이것은 교과서 동적 프로그래밍 문제이며 간단한 DP로 해결하기에 충분합니다.

  • 각 숫자에서 다른 숫자로의 최소 변화를 계산 한 후에는 기본적으로 약간의 변형 된 TSP (여행사 문제)가 남아 있습니다. 운 좋게도,이 단계에는 무차별 대 입력으로 충분할 정도로 적은 수의 노드 (가장 어려운 테스트 사례에서는 최대 5 개)가 있습니다.

ungolfed 코드 (많이 주석 처리됨)

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
멋진 답변! Rust에 관심이 있으며 설명은 실제로 학습에 매우 도움이됩니다. 그리고 머리말처럼으로 구문 강조를 얻을 수 있습니다 <!-- language-all: lang-rust -->. ;)
Alex A.

나는 해결책을 연구 중이며이 C와 같은 의사 코드와 같이 매우 작은 조회 테이블을 사용하여 O (1)에서 최소 중량에서 고 중량에 대한 최소 변화량을 쉽게 계산할 수 있음을 알았습니다 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

while 루프 대신 필터를 사용하기 때문에 파이썬 버전보다 속도가 느립니다. 곧 설명하겠습니다. 이제 파이썬 코드를보십시오.

온라인으로 사용해보십시오 .

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

작은 것들에서 작동하지만 큰 것들에서 완성되지 못했습니다.


코드를 제대로 읽지 못했지만 y5공백을 절약하기 위해 10을 바꿀 수 있습니까?
Sp3000

@ Sp3000 공백을 절약하지만 전반적인 문자는 저장하지 않습니다. 그러나 나는 저장하여 목록을 압축하여 문자를 저장할 수 있다고 생각합니다K=5
Maltysen

이 솔루션은 "솔루션이 몇 분 안에 예제 테스트 사례를 해결해야합니다"라는 규칙을 따르지 않습니다. (인용
부호

0

C ++-863 바이트, ungolfed

이것은 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.