สร้างกริดไฟฟ้า


22

ความท้าทาย

มีเมือง N อยู่ในแนวตรง เมือง i-th ตั้งอยู่A[i]กิโลเมตรไปทางขวาของแหล่งกำเนิด ไม่มีเมืองใดอยู่ในที่เดียวกัน

คุณกำลังจะสร้างกริดไฟฟ้ากับโรงไฟฟ้าบางแห่ง โรงไฟฟ้าจะต้องสร้างขึ้นภายในเมือง อย่างไรก็ตามคุณได้รับอนุญาตให้สร้างKโรงไฟฟ้า (<N) เท่านั้นจึงจะมีบางเมืองที่ไม่มีโรงไฟฟ้า สำหรับเมืองที่มีโรงไฟฟ้าแต่ละไม่มีคุณต้องสร้างสายเคเบิลระหว่างมันและเมืองที่ใกล้ที่สุดที่มีโรงไฟฟ้า

ตัวอย่างเช่นหากมีสามเมืองที่ตั้งอยู่0, 1, 2และมีเพียงเมืองที่0มีโรงไฟฟ้าคุณต้องสร้างสายเคเบิลสองสายหนึ่งจาก2ถึง0(2 กม.) และอีกแห่งจาก1ถึง0(1 กม.) ซึ่งมีความยาวรวม 3 กม. .

ให้Kและตำแหน่งของเมือง ( A) คุณควรคำนวณกิโลเมตรขั้นต่ำของสายเคเบิลที่คุณต้องการในการสร้างตาราง

ตัวอย่างผลงาน

K = 1, A = [0, 2, 4, 6, 8] : 12 
# build power plant in the city at position 4, total length = 4 + 2 + 0 + 2 + 4 = 12

K = 3, A = [0, 1, 10, 11, 20, 21, 22, 30, 32] : 23
# build power plants in cities at positions 0, 10 and 22

K = 5, A = [0, 1, 3, 6, 8, 11, 14] : 3
# build power plants in all cities except those at positions 0, 3

K = 6, A = [0, 1, 3, 6, 8, 14, 15, 18, 29, 30, 38, 41, 45, 46, 49, 58, 66, 72, 83, 84] : 49

ข้อมูลจำเพาะ

  • คุณควรใช้ฟังก์ชั่นหรือโปรแกรมที่ใช้จำนวนเต็มบวกKและรายการจำนวนเต็มAในรูปแบบใด ๆ และส่งออก / กลับจำนวนเต็มแทนคำตอบ

  • A เรียงตามลำดับจากน้อยไปมากและองค์ประกอบทั้งหมดเป็นจำนวนเต็มไม่เป็นลบ

  • A[0] = 0และA[N-1]จะไม่เกิน 1,000N

  • โปรดทราบว่าเอาต์พุตจะมีขนาด 1,000N 2ดังนั้นในกรณีที่มีขนาดใหญ่กว่าคุณอาจต้องใช้จำนวนเต็ม 64 บิตในบางภาษา

  • ไม่อนุญาตให้ใช้มัลติเธรด(ฉันจะตั้งค่าความสัมพันธ์ของโปรแกรมของคุณเป็น 1 คอร์เมื่อตัดสิน) อนุญาตการปรับให้เหมาะสมของคอมไพเลอร์ (เช่น-O2ใน C)

เกณฑ์การให้คะแนน

  • ฉันจะจับเวลารหัสของคุณบนคอมพิวเตอร์ของฉัน (Ubuntu 16.04 พร้อมโปรเซสเซอร์ Intel i7-3770S) พร้อมขนาดทดสอบที่แตกต่างกัน โดยเฉพาะฉันจะสร้างการทดสอบด้วย N = floor (2 x / 5 ) โดยที่ x เป็นจำนวนเต็มบวก
    คะแนนของคุณจะเป็นค่า x ของ testcase ที่เล็กที่สุดที่โปรแกรมของคุณใช้มากกว่า 10 วินาทีหรือ 1 GiB ของหน่วยความจำหรือไม่ได้ให้คำตอบที่ถูกต้อง

    • คำตอบที่ได้คะแนนสูงสุดจะเป็นฝ่ายชนะ หากคำตอบสองข้อได้รับคะแนนเท่ากันคำตอบก่อนหน้านี้จะชนะ
  • โปรแกรมทั้งหมดจะถูกตัดสินโดยชุดทดสอบเดียวกัน

  • รู้สึกฟรีเพื่อโพสต์ scorings ของคุณเอง สนับสนุนการอธิบายขั้นตอนวิธีของคุณ

โบนัส

นี้เป็นของฉันโปรแกรมภาษา C ++ มันคะแนน108 คุณสามารถตรวจสอบสรุปย่อย SHA-256 ได้9a87fa183bad1e3a83d2df326682598796a216b3a4262c32f71dfb06df12935dด้วยส่วนรหัสทั้งหมด (ไม่มีส่วนท้าย) ในลิงก์

อัลกอริทึมรวมการค้นหาแบบไบนารีและการเพิ่มประสิทธิภาพของ Knuth เพื่อหาบทลงโทษที่ถูกต้องของแต่ละโรงงานเพื่อรับจำนวนที่ต้องการ ความซับซ้อนคือ O (N log N log A [N-1]) ฉันรู้สึกประหลาดใจว่าโปรแกรมที่ได้คะแนนสูงกว่าO (n log [N-1]) วิธีการแก้ปัญหาโดย Anders Kaseorg อาจเป็นเพราะข้อเท็จจริงที่ว่ากรณีบันทึกในการเพิ่มประสิทธิภาพของ Knuth จะไม่เกิดขึ้น

โปรดทราบว่าความท้าทายนี้เป็นเช่นเดียวกับIOI 2000 ที่ทำการไปรษณีย์ แม้ว่าข้อ จำกัด เดิมคือ N <= 300 และ K <= 30 แม้ว่า


2^^(x/5): หมายความว่าอะไร ? คุณสามารถให้ขอบเขตบนสำหรับ N ได้ไหม
Setop

1
@Setop ตัวอย่างเช่นหากโปรแกรมของคุณสามารถจัดการได้N=21( = floor(2^(22/5)) )ภายใน 10 วินาที แต่ไม่สามารถจัดการได้N=24( = floor(2^(23/5)) )ดังนั้น 23 คะแนนจะเป็นคะแนน ฉันไม่ได้ใช้ขอบบนเนื่องจากความแตกต่างระหว่างอัลกอริทึมที่แตกต่างกันมากเกินไป ตัวอย่างเช่นถ้าผมตั้ง N <= 40 จะมีความแตกต่างเล็ก ๆ น้อย ๆ ระหว่างO(KN^2)และO(KN^3)แต่O(2^N)จะไม่ได้เสร็จสิ้นในเวลากันเอง
Colera Su

5
นี่เป็นสิ่งที่ฉันทำเพื่อหาเลี้ยงชีพและฉันสามารถบอกคุณได้ว่านี่ไม่ใช่วิธีที่เราออกแบบตารางไฟฟ้า!
Stewie Griffin


3
ความท้าทายที่ยอดเยี่ยมระบบการให้คะแนนที่ยอดเยี่ยม ทำได้ดี!
isaacg

คำตอบ:


9

สนิมคะแนน = 104

นี่เป็นการใช้งานอัลกอริทึมที่บันทึกโดยGrønlundและคณะ (2017)ในตอนท้ายของ .33.3.1 แม้ว่าฉันจะต้องติดตามสายการอ้างอิงที่ยาวและกรอกรายละเอียดที่ขาดหายไป มันทำงานในเวลาO ( N log A [ N - 1])

rustc -Oคอมไพล์ด้วย รูปแบบอินพุตอยู่Kบนบรรทัดแรกตามด้วยรายการAหนึ่งรายการต่อบรรทัดทั้งหมดบน stdin

(หมายเหตุ: ฉันส่งข้อมูลนี้ภายในหนึ่งชั่วโมงหลังจากกำหนดเวลาสิ้นสุด แต่ฉันคาดว่ารุ่นสุดท้ายที่ฉันส่งก่อนกำหนดส่งเงินรางวัลซึ่งวิ่งในเวลาO ( N log N log A [ N - 1]) ให้คะแนนประมาณ 94 .)

use std::cmp::min;
use std::io::{self, BufRead};
use std::iter::{once, Cloned};
use std::num::Wrapping;
use std::ops::Range;
use std::slice;
use std::time::Instant;
use std::u64;

type Cost = u64;
const INF: Cost = u64::MAX;

trait ColsTrait<Col>: Clone {
    type Iter: Iterator<Item = Col>;
    fn len(&self) -> usize;
    fn iter(&self) -> Self::Iter;
    fn slice(&self, range: Range<usize>) -> Self;
}

impl<'a, Col: Clone> ColsTrait<Col> for &'a [Col] {
    type Iter = Cloned<slice::Iter<'a, Col>>;
    fn len(&self) -> usize {
        (*self).len()
    }
    fn iter(&self) -> Self::Iter {
        (*self).iter().cloned()
    }
    fn slice(&self, range: Range<usize>) -> Self {
        unsafe { self.get_unchecked(range) }
    }
}

impl ColsTrait<usize> for Range<usize> {
    type Iter = Range<usize>;
    fn len(&self) -> usize {
        self.end - self.start
    }
    fn iter(&self) -> Range<usize> {
        self.clone()
    }
    fn slice(&self, range: Range<usize>) -> Self {
        Range {
            start: self.start + range.start,
            end: self.start + range.end,
        }
    }
}

fn smawk<Col: Copy, Cols: ColsTrait<Col>, Key: Ord, F: Copy + Fn(usize, Col) -> Key>(
    n: usize,
    shift: u32,
    cols: Cols,
    f: F,
) -> Vec<usize> {
    if n == 0 {
        Vec::new()
    } else if cols.len() > n {
        let mut s = Vec::with_capacity(n);
        let mut sk = Vec::with_capacity(n);
        for (jk, j) in cols.iter().enumerate() {
            while match s.last() {
                Some(&l) => f(!(!(s.len() - 1) << shift), j) <= f(!(!(s.len() - 1) << shift), l),
                None => false,
            } {
                s.pop();
                sk.pop();
            }
            if s.len() < n {
                s.push(j);
                sk.push(jk);
            }
        }
        smawk1(
            n,
            shift,
            cols,
            f,
            smawk(n / 2, shift + 1, &s[..], f)
                .into_iter()
                .map(|h| unsafe { *sk.get_unchecked(h) }),
        )
    } else {
        smawk1(
            n,
            shift,
            cols.clone(),
            f,
            smawk(n / 2, shift + 1, cols, f).into_iter(),
        )
    }
}

fn smawk1<
    Col: Copy,
    Cols: ColsTrait<Col>,
    Key: Ord,
    F: Fn(usize, Col) -> Key,
    Iter: Iterator<Item = usize>,
>(
    n: usize,
    shift: u32,
    cols: Cols,
    f: F,
    iter: Iter,
) -> Vec<usize> {
    let mut out = Vec::with_capacity(n);
    let mut range = 0..0;
    for (i, k) in iter.enumerate() {
        range.end = k + 1;
        out.push(
            range
                .clone()
                .zip(cols.slice(range.clone()).iter())
                .min_by_key(|&(_, col)| f(!(!(2 * i) << shift), col))
                .unwrap()
                .0,
        );
        out.push(k);
        range.start = k;
    }
    if n % 2 == 1 {
        range.end = cols.len();
        out.push(
            range
                .clone()
                .zip(cols.slice(range.clone()).iter())
                .min_by_key(|&(_, col)| f(!(!(n - 1) << shift), col))
                .unwrap()
                .0,
        );
    }
    out
}

fn solve(k: usize, a: &[Cost]) -> Cost {
    if k >= a.len() {
        return 0;
    }
    let sa = once(Wrapping(0))
        .chain(a.iter().scan(Wrapping(0), |s, &x| {
            *s += Wrapping(x);
            Some(*s)
        }))
        .collect::<Vec<_>>();
    let c = |i: usize, j: usize| {
        let h = (i - j) / 2;
        unsafe {
            (sa.get_unchecked(i) - sa.get_unchecked(i - h) - sa.get_unchecked(j + h)
                + sa.get_unchecked(j))
                .0
        }
    };
    let cost1 = c(a.len(), 0);
    if k == 1 {
        return cost1;
    }
    let cost2 = (1..a.len()).map(|j| c(j, 0) + c(a.len(), j)).min().unwrap();
    let mut low = 0;
    let mut high = cost1 - cost2;
    let mut ret = INF;
    while low <= high {
        let penalty = low + (high - low) / 2;
        let mut out = vec![(INF, 0); a.len() + 1];
        out[0] = (0, 0);
        let mut begin = 0;
        let mut chunk = 1;
        loop {
            let r = min(a.len() + 1 - begin, 2 * chunk);
            let edge = begin + chunk;
            let (out0, out1) = out.split_at_mut(edge);
            let f = |i: usize, j: usize| {
                let h = (edge + i - j) / 2;
                let &(cost, count) = unsafe { out0.get_unchecked(j) };
                (
                    cost.saturating_add(
                        unsafe {
                            sa.get_unchecked(edge + i) - sa.get_unchecked(edge + i - h)
                                - sa.get_unchecked(j + h)
                                + sa.get_unchecked(j)
                        }.0 + penalty,
                    ),
                    count + 1,
                )
            };
            for ((i, j), o) in smawk(r - chunk, 0, begin..edge, &f)
                .into_iter()
                .enumerate()
                .zip(out1.iter_mut())
            {
                *o = min(f(i, begin + j), *o);
            }
            let x = unsafe { out1.get_unchecked(r - 1 - chunk) };
            if let Some(j) = (edge..begin + r - 1).find(|&j| &f(r - 1 - chunk, j) <= x) {
                begin = j;
                chunk = 1;
            } else if r == a.len() + 1 - begin {
                break;
            } else {
                chunk *= 2;
            }
        }
        let &(cost, count) = unsafe { out.get_unchecked(a.len()) };
        if count > k {
            low = penalty + 1;
        } else {
            ret = cost.wrapping_sub(k as Cost * penalty);
            if count == k {
                return ret;
            }
            high = penalty - 1;
        }
    }
    ret
}

fn main() {
    let stdin = io::stdin();
    let mut lines = stdin.lock().lines();
    let k = lines.next().unwrap().unwrap().parse().unwrap();
    let a = lines
        .map(|s| s.unwrap().parse().unwrap())
        .collect::<Vec<_>>();
    let start = Instant::now();
    let cost = solve(k, &a);
    let time = start.elapsed();
    println!(
        "cost: {}\ntime: {}.{:09} sec",
        cost,
        time.as_secs(),
        time.subsec_nanos()
    );
}

ลองออนไลน์!

สนิมคะแนนก่อนสอบ = 73

rustc -Oคอมไพล์ด้วย รูปแบบอินพุตอยู่Kบนบรรทัดแรกตามด้วยรายการAหนึ่งรายการต่อบรรทัดทั้งหมดบน stdin

use std::io::{self, BufRead};
use std::iter::once;
use std::num::Wrapping;
use std::time::Instant;
use std::u64;

type Cost = u64;
const INF: Cost = u64::MAX;

fn smawk<Col: Clone, Key: Ord, F: Clone + Fn(usize, &Col) -> Key>(
    n: usize,
    shift: u32,
    cols: &[Col],
    f: F,
) -> Vec<usize> {
    if n == 0 {
        Vec::new()
    } else if cols.len() > n {
        let mut s = Vec::with_capacity(n);
        let mut sk = Vec::with_capacity(n);
        for (jk, j) in cols.iter().enumerate() {
            while match s.last() {
                Some(l) => f(!(!(s.len() - 1) << shift), j) <= f(!(!(s.len() - 1) << shift), l),
                None => false,
            } {
                s.pop();
                sk.pop();
            }
            if s.len() < n {
                s.push(j.clone());
                sk.push(jk);
            }
        }
        smawk1(
            n,
            shift,
            cols,
            f.clone(),
            smawk(n / 2, shift + 1, &s, f)
                .into_iter()
                .map(|h| unsafe { *sk.get_unchecked(h) }),
        )
    } else {
        smawk1(
            n,
            shift,
            cols,
            f.clone(),
            smawk(n / 2, shift + 1, &cols, f).into_iter(),
        )
    }
}

fn smawk1<Col: Clone, Key: Ord, F: Clone + Fn(usize, &Col) -> Key, Iter: Iterator<Item = usize>>(
    n: usize,
    shift: u32,
    cols: &[Col],
    f: F,
    iter: Iter,
) -> Vec<usize> {
    let mut out = Vec::with_capacity(n);
    let mut range = 0..0;
    for (i, k) in iter.enumerate() {
        range.end = k + 1;
        out.push(
            range
                .clone()
                .zip(unsafe { cols.get_unchecked(range.clone()) })
                .min_by_key(|&(_, col)| f(!(!(2 * i) << shift), col))
                .unwrap()
                .0,
        );
        out.push(k);
        range.start = k;
    }
    if n % 2 == 1 {
        range.end = cols.len();
        out.push(
            range
                .clone()
                .zip(unsafe { cols.get_unchecked(range.clone()) })
                .min_by_key(|&(_, col)| f(!(!(n - 1) << shift), col))
                .unwrap()
                .0,
        );
    }
    out
}

fn solve(k: usize, a: &[Cost]) -> Cost {
    let mut cost = vec![INF; a.len() + 1 - k];
    let sa = once(Wrapping(0))
        .chain(a.iter().scan(Wrapping(0), |s, &x| {
            *s += Wrapping(x);
            Some(*s)
        }))
        .collect::<Vec<_>>();
    cost[0] = 0;
    let cols = (0..a.len() + 1 - k).collect::<Vec<_>>();
    for m in 0..k {
        cost = {
            let f = |i: usize, &j: &usize| {
                if i + 1 >= j {
                    let h = (i + 1 - j) / 2;
                    unsafe {
                        cost.get_unchecked(j).saturating_add(
                            (sa.get_unchecked(i + m + 1) - sa.get_unchecked(i + m + 1 - h)
                                - sa.get_unchecked(j + m + h)
                                + sa.get_unchecked(j + m))
                                .0,
                        )
                    }
                } else {
                    INF
                }
            };
            smawk(a.len() + 1 - k, 0, &cols, &f)
                .into_iter()
                .enumerate()
                .map(|(i, j)| f(i, &j))
                .collect()
        };
    }
    cost[a.len() - k]
}

fn main() {
    let stdin = io::stdin();
    let mut lines = stdin.lock().lines();
    let k = lines.next().unwrap().unwrap().parse().unwrap();
    let a = lines
        .map(|s| s.unwrap().parse().unwrap())
        .collect::<Vec<_>>();
    let start = Instant::now();
    let cost = solve(k, &a);
    let time = start.elapsed();
    println!(
        "cost: {}\ntime: {}.{:09} sec",
        cost,
        time.as_secs(),
        time.subsec_nanos()
    );
}

ลองออนไลน์!


คุณได้มีคะแนนก่อนการทดลองแต่นั่นเป็นเพราะการล้นของ61 u32คุณอาจเปลี่ยนเป็นประเภทจำนวนเต็ม 64 บิตได้ไหม
Colera Su

@ColeraSu มันจะดีกว่าไหมถ้าฉันtype Cost = u32จะเปลี่ยนเป็นtype Cost = u64?
Anders Kaseorg

1
ว้าวฉันไม่เคยนึกถึงอัลกอริธึม SMAWK มาก่อน 73งานที่ดีที่คุณได้
Colera Su

2
@ngn คุณมีอะไรกับสนิม :-(
Anders Kaseorg

1
ขอแสดงความยินดีกับการชนะรางวัลแรก!
Decurous

5

C, คะแนน = 56

เนื้อหาของa.c:

typedef void V;typedef char C;typedef long L;typedef unsigned long U;
#define R return
#define W while
#define S static
#include<sys/syscall.h>
#define h1(f,x    )({L r;asm volatile("syscall":"=a"(r):"0"(SYS_##f),"D"(x)              :"cc","rcx","r11","memory");r;})
#define h3(f,x,y,z)({L r;asm volatile("syscall":"=a"(r):"0"(SYS_##f),"D"(x),"S"(y),"d"(z):"cc","rcx","r11","memory");r;})
#define read(a...) h3(read ,a)
#define write(a...)h3(write,a)
#define exit(a...) h1(exit ,a)
S V P(U x){C s[32],*p=s+32;*--p='\n';do{*--p='0'+x%10;x/=10;}W(x);write(1,p,s+32-p);}
S V mc(V*x,V*y,L n){C*p=x,*q=y;for(L i=0;i<n;i++)p[i]=q[i];}
#define min(x,y)({typeof(x)_x=(x),_y=(y);_x+(_y-_x)*(_y<_x);})
#define t(x,i,j)x[(i)*(n+n-(i)+1)/2+(j)] //triangle indexing
#define x(i,j)t(x,i,j)
#define y(i,j)t(y,i,j)
#define z(i,j)t(z,i,j)
#define N 4096 //max
L n;U ka[N+1],c[N],x[N*(N+1)/2],y[N*(N+1)/2],z[N*(N+1)/2];
V _start(){
 C s[1<<20];L r=0;U v=0;
 W(0<(r=read(0,s,sizeof(s))))for(L i=0;i<r;i++)if('0'<=s[i]&&s[i]<='9'){v=s[i]-'0'+10*v;}else{ka[n++]=v;v=0;}
 n--;U k=*ka,*a=ka+1;
 for(L i=n-1;i>=0;i--)for(L j=i-1;j>=0;j--)x(j,i)=x(j+1,i)-a[j]+a[i];
 for(L i=0;i<n;i++)for(L j=i+1;j<n;j++)y(i,j)=y(i,j-1)+a[j]-a[i];
 for(L i=n-1;i>=0;i--)for(L j=i+1;j<n;j++){
  U v=~0ul,*p=&x(i,i),*q=&y(i,j);for(L l=i;l<j;l++){v=min(v,*p+++*q);q+=n-l;} //min(v,x(i,l)+y(l,j));
  z(i,j)=v;}
 mc(c,z,8*n);
 for(L m=1;m<k;m++)for(L j=n-1;j>=m;j--){
  U v=~0ul,*p=&z(j,j);for(L i=j-1;i>=m-1;i--){v=min(v,c[i]+*p);p-=n-i;} //min(v,c[i]+z(i+1,j))
  c[j]=v;}
 P(c[n-1]);exit(0);}

เชลล์สคริปต์เพื่อรวบรวมและทดสอบข้างต้น:

#!/bin/bash -e
clang -O3 -nostdlib -ffreestanding -fno-unwind-tables -fno-unroll-loops -fomit-frame-pointer -oa a.c
strip -R.comment -R'.note*' a;stat -c'size:%s' a
t(){ r="$(echo "$1"|./a)";if [ "$r" != "$2" ];then echo "in:$1, expected:$2, actual:$r";fi;} #func tests
t '1 0 2 4 6 8' 12
t '3 0 1 10 11 20 21 22 30 32' 23
t '5 0 1 3 6 8 11 14' 3
t '6 0 1 3 6 8 14 15 18 29 30 38 41 45 46 49 58 66 72 83 84' 49
t '2 0 7 9' 2
for n in 1176 1351 1552 1782 2048;do #perf test
 echo "n:$n";a=0 inp="$((2*n/3))" RANDOM=1;for i in `seq $n`;do inp="$inp $a";a=$((a+=RANDOM%1000));done
 ulimit -t10 -v1048576;time ./a<<<"$inp"
done

n = 776 ใช้เวลา 6.2 วินาที, n = 891 ใช้เวลา 12 วินาที

n = 1176 ใช้เวลา 5.9 วินาที, n = 1351 ใช้เวลามากกว่า 10 วินาที

n = 1351 ใช้เวลา 8.7s, n = 1552 ใช้เวลามากกว่า 10 วินาที (ด้วย k = 2 * n / 3) บนของฉัน Intel(R) Core(TM) i3-2375M CPU @ 1.50GHz


2
ฉันคิดว่านี่ไม่ใช่ code-golf ใช่ไหม
user202729

@ user202729 มันเป็นวิธีที่ผมปกติเขียนรหัส C - ช่วงแรกสไตล์
ngn

@ngn ฉันคิดว่าคุณแล้วโดยปกติแล้วจะไม่ใช้การเน้นไวยากรณ์ใด ๆ
Jonathan Frech

@ JonathanFrech จริง ๆ แล้วฉันทำ ฉันปรับแต่งsyntax/c.vimแล้ว
ngn

2
@cole นี่เป็นเพียง C ปกติ, หนาแน่นขึ้นเท่านั้น หากคุณคุ้นเคยกับภาษาคุณควรอ่านได้โดยไม่ยากแม้จะช้ากว่าเดิมหลายครั้งเนื่องจากหนึ่งบรรทัดในที่นี้มีข้อมูลโปรแกรมเมอร์ C ส่วนใหญ่จะแพร่กระจายเกิน 5-10 บรรทัด (เสียเปล่า!) ฉันเขียนความคิดเห็นเฉพาะบิตที่ยากที่สุดเท่านั้น
ngn

3

C ++, คะแนน = 53

การแก้ปัญหาที่ฉันได้กล่าวไว้ในความคิดเห็น O(n²×k). (ตอนนี้ฉันลบมันเพราะมันไม่จำเป็น) O(n×k)อาจจะลดลง

อินพุตค่อนข้างยืดหยุ่นในบรรทัดแรกหมายเลขแรกคือkตัวเลขอื่นเป็นรายการของอาร์เรย์aแต่ถ้าพบวงเล็บปิดใด ๆ จะหยุดอ่านอินพุต ดังนั้นการป้อนข้อมูลจึงK = 1, A = [0, 2, 4, 6, 8] : 12เป็นที่ยอมรับ

// /codegolf/149029/build-an-electrical-grid

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

bool read(std::istream& str, int& x) {

    char ch;

    do {
        if (str >> x) return true;
        if (str.eof()) return false;
        str.clear(); // otherwise it's probably int parse error
    } while (str >> ch && ch != ']' && ch != ')' && ch != '}');
    // ignore 1 character, but treat any close parentheses as end of input

    // cannot read anything now
    return false;
}

int main() {
    int k; std::vector<int> a;

    //{ Read input
    std::string st; std::getline(std::cin, st);
    std::stringstream sst (st);

    read(sst, k);

    int x;
    while (read(sst, x)) a.push_back(x);
    //}

    std::vector<std::vector<int>> dp (a.size(), std::vector<int>(k));
    // dp[n][k] = min distance you can get for cities [n..a.size()-1]
    // and [k+1] power plants, and city [n] has a power plant.

    // sum_array[x] = sum of coordinates of cities [x..a.size()-1]
    std::vector<int> sum_array (a.size()+1);
    sum_array.back() = 0;
    for (int n = a.size(); n --> 0;)
        sum_array[n] = sum_array[n+1] + a[n];

    for (int n = a.size(); n --> 0;) {
        for (int k1 = k; k1 --> 0;) {
            if (k1 == 0) {
                int nWire = a.size() - 1 - n;
                dp[n][k1] = sum_array[n+1] - nWire * a[n];
            } else {
            // unindent because my screen width is limited

dp[n][k1] = INT_MAX / 2; // avoid stupid overflow error (in case of -ftrapv)

// let [n1] be the next position for a power plant
int first_connect_right = n; // < lengthy variable name kills screen width
// ^ lengthy comment kills screen width

for (int n1 = n + 1; n1 < (int)a.size(); ++n1) {

    while (a[first_connect_right]-a[n] < a[n1]-a[first_connect_right]) ++first_connect_right;

    int nRightWire = n1 - first_connect_right, nLeftWire = first_connect_right - 1 - n;
    dp[n][k1] = std::min(dp[n][k1],
        a[n1]*nRightWire-(sum_array[first_connect_right]-sum_array[n1]) +
        (sum_array[n+1]-sum_array[first_connect_right])-a[n]*nLeftWire +
        dp[n1][k1-1]
    );

}

            }

        }
    }

    int ans = INT_MAX;
    for (int n = a.size()+1-k; n --> 0;) {
        ans = std::min(ans, dp[n].back() + a[n]*n-sum_array[0]+sum_array[n]);
    }

    std::cout << ans << '\n';

    return 0;
}

ลองออนไลน์!

สร้างกรณีทดสอบแบบสุ่ม (อินพุตNและช่วงเมืองเป็นทางเลือก1000×Nโดยค่าเริ่มต้น)


ถ้ามันเกิดขึ้นเพื่อให้สามารถแก้ปัญหาบางกรณีทดสอบขนาดใหญ่ผมจะมีการเปลี่ยนแปลงที่จำเป็นintเพื่อint64_ts
user202729

dp [runned_n, runned_k] = ขั้นต่ำ {dp [runned_n-x, runned_k] + f [x, n]} ดังนั้นการเขียนโปรแกรมแบบไดนามิกโดยตรงคือ O (n ^ 2 * k) อาจต้องเปลี่ยนวิธีทั้งหมดเพื่อลดความซับซ้อน?
l4m2

@ l4m2 อย่าทำให้เสียอัลกอริทึม! (เงินรางวัลยังไม่หมดอายุ)
user202729

ขออภัยฉันไม่ทราบว่า "เสีย" ของคุณหมายถึง "ทิ้ง" หรือ "ขโมย" หรือทั้งสองอย่าง สามารถค้นหาความหมายทั้งสอง ฉันไม่ค่อยรู้คำนี้ (ผมเคยคิดว่ายังมีเงินรางวัลวิธีการที่ถูกผูกไว้)
l4m2

2
เครื่องกำเนิดการทดสอบแบบสุ่มไม่บังคับใช้ [0] = 0 เหมือนคำถามที่ระบุ
Anders Kaseorg

2

C #, คะแนน = 23

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

using Combinatorics.Collections;
using System;

namespace ElectricalGrid
{
    class Program
    {
        static void Main(string[] args)
        {
            if (Build(1, new long[] { 0, 2, 4, 6, 8 }) == 12)
                Console.WriteLine("OK");
            else
                Console.WriteLine("ERROR");
            if (Build(3, new long[] { 0, 1, 10, 11, 20, 21, 22, 30, 32 }) == 23)
                Console.WriteLine("OK");
            else
                Console.WriteLine("ERROR");
            if (Build(5, new long[] { 0, 1, 3, 6, 8, 11, 14 }) == 3)
                Console.WriteLine("OK");
            else
                Console.WriteLine("ERROR");
            if (Build(6, new long[] { 0, 1, 3, 6, 8, 14, 15, 18, 29, 30, 38, 41, 45, 46, 49, 58, 66, 72, 83, 84 }) == 49)
                Console.WriteLine("OK");
            else
                Console.WriteLine("ERROR");

            Console.ReadKey();
        }

        static long Build(int k, long[] a)
        {
            var combs = new Combinations<long>(a, k);
            var totalDist = long.MaxValue;
            foreach (var c in combs)
            {
                long tempDist = 0;
                foreach (var i in a)
                {
                    var dist = long.MaxValue;
                    foreach (var e in c)
                    {
                        var t = Math.Abs(i - e);
                        if (t < dist) dist = t;
                    }
                    tempDist += dist;
                }
                if (tempDist < totalDist) totalDist = tempDist;
            }
            return totalDist;
        }
    }
}

คำอธิบายง่ายๆจริง ๆ : สำหรับการรวมกันcของkองค์ประกอบแต่ละตัวaคำนวณผลรวมของระยะทางจากแต่ละองค์ประกอบขององค์ประกอบaที่ใกล้ที่สุดcและกลับมารวมกันด้วยระยะทางรวมน้อยที่สุด

วิธีการแบบหนึ่งซับในBuild(อาจช้ากว่ารุ่นขยายซึ่งจำเป็นต้องเพิ่มการอ้างอิงSystem.Linq):

static long Build(int k, long[] a)
{
    return new Combinations<long>(a, k).Min(c => a.Sum(i => c.Min(e => Math.Abs(i - e))));
}

2

C ++, คะแนน = 48

#include <stdio.h>
#include <queue>
#include <algorithm>
typedef long long ull;
typedef unsigned int uint;
uint A[1<<20];
ull S[1<<20];

double ky = 1;
struct point {
    ull dist;
    int n;
    inline point() {}
    inline point(ull dist, int n): dist(dist), n(n) {}
    inline double res() const{
        return dist + n * ky;
    }
    inline int operator<(const point& other) const {
        return res() < other.res();
    }
} V[1<<20];
inline ull f(int L, int R) {
    int m = L+R+1 >> 1;
    return (S[R]-S[m]) - A[m]*(R-m) +
           A[m]*(m-L) - (S[m]-S[L]);
}
int main() {
    int N, K, i, j, p;
    scanf ("%d%d", &N, &K);
    ull s = 0;
    for (i=1; i<=N; i++) {
        scanf ("%u", A+i);
        S[i] = s += A[i];
    }
    double kyL = 0, kyH = 1e99;
    point cL, cR;
    for (int step=0; step++<50; ky = std::min(ky*2, (kyL+kyH)*.5)) {
        for (i=1; i<=N; i++) {
            point tmp(f(0,i), 1);
            for (j=1; j<i; j++) {
            //printf("ky=%f [%d]=%d %I64d %f\n", ky, i, tmp.n, tmp.dist, tmp.res());
                point cmp = V[j];
                cmp.dist += f(j, i);
                cmp.n ++;
                if (cmp<tmp) tmp=cmp;
            }
            //printf("ky=%f [%d]=%d %I64d %f\n", ky, i, tmp.n, tmp.dist, tmp.res());
            V[i] = tmp;
        }
        if (V[N].n == K) {
_:          return! printf("%I64d", V[N].dist);
        }
        if (V[N].n > K) {
            kyL = ky;
            cL = V[N];
        } else {
            kyH = ky;
            cR = V[N];
        }
        //printf("ky=%f %d %I64d %f\n", ky, V[N].n, V[N].dist, V[N].res());
        //getch();
    }
    V[N].dist = (double)cL.dist / (cR.n-cL.n) * (K-cL.n) +
                (double)cR.dist / (cL.n-cR.n) * (K-cR.n) + .5;
    printf("%I64d", V[N].dist);
}

อินพุตการใช้งาน: NKA [1] A [2] ... A [N]


2
หากคุณเพิ่มขีด จำกัด ของstep70 เป็นคะแนนทดสอบของคุณคือ 60
Colera Su


2

JavaScript (ES6) (Node.js)คะแนน = 10

อัลกอริทึมใหม่จะอธิบายว่ามันใช้งานได้จริงในเวลานี้

const {performance} = require('perf_hooks');

class Connection{
    constructor(left,index,length,right){
        if(typeof right === 'undefined'){
            this._distance = 0;
        } else {
            this._distance = typeof left === 'undefined' ? 0 :
                    Math.abs(right - left);
        }
        var half = Math.floor(length/2);
        if(length % 2 < 1){
            this._magnitude = half - Math.abs(index - half + 1);
        } else {
            var temp = index - half;
            this._magnitude = half - Math.abs(temp >= 0 ?temp:temp + 1);
        }
        this._value = this.distance * this.magnitude;
    }

    get distance(){return this._distance;};
    get magnitude(){return this._magnitude;};
    set magnitude(value){
        this._magnitude = value;
        this._value = this.distance * this.magnitude;
    };
    valueOf(){return this._value};
}

class Group{
	constructor(...connections){
        this._connections = connections;
		
		this._max = Math.max(...connections); //uses the ValueOf to get the highest Distance to the Left
	}
	get connections(){return this._connections;};
	get max(){return this._max;};
    cutLeft(index){

            for(let i=1,j=index-1;;i++){
                
                if(typeof this.connections[j] === 'undefined' || this.connections[j].magnitude <= i){
                    break;
                }
                this.connections[j].magnitude = i;
                j--;
            }

    }

    cutRight(index){

            for(let i=0,j=index;;i++){
                
                if(typeof this.connections[j] === 'undefined' || this.connections[j].magnitude <= i){
                    break;
                }
                this.connections[j].magnitude = i;
                j++;
            }

    }

    static of(...connections){
        return new Group(...connections.map((c,i)=>new Connection(c.distance,i,connections.length)));
    }

	split(){
        var index = this.connections.findIndex(c=>c.valueOf() == this.max);
        if(index < 0){
            return;
        }
        var length = this.connections.length;
        var magnitude = this.connections[index].magnitude;

        this.cutLeft(index);
        this.cutRight(index);
        this._max = Math.max(...this.connections);
	}

    center(){
        if(typeof this._center === 'undefined'){
            this._center = this.connections.reduce((a,b)=>a==0?b.valueOf():a.valueOf()+b.valueOf(),0);
        }
        return this._center;
    }

    valueOf(){return this._max;};
    toString(){
        var index = this.connections.findIndex(c=>c.valueOf() == this.max);
        var value = this.connections[index].magnitude;
        var ret = '';
        for(let i = 0;i<value;i++){
            ret += this.connections.map(c=>{return (i<c.magnitude)?c.distance:' ';}).reduce((a,b)=>a==''?b:a+'-'+b,'') + '\n';
        }
        return ret;
    };
}

function crunch(plants, cities){
	var found = [];
    var size = cities.length;
    cities = cities.map((city,i,arr)=> new Connection(city,i,size,arr[i+1])).slice(0,cities.length-1);
    var group = new Group(...cities);
    for(;plants>1;plants--){
    group.split();
    }
    console.log(`Wire Length Needed: ${group.center()}`);
}

function biggestGroup(groups){
	return groups.find(g => g[g.length-1].orig - g[0].orig);
}

function* range (start, end, limit) {
    while (start < end || typeof limit !== 'undefined' && limit-- > 0) {
        yield start
        start += 1 + Math.floor(Math.random()*100);
    }
}

function* cities (score){
	let n = Math.floor(Math.pow(2,score/5));
	var start = 0;
	while (n-- > 0 && start <= (1000 * n)) {
		yield start;
        start += 1 + Math.floor(Math.random()*100);
    }
}


if(typeof process.argv[3] === 'undefined'){
    crunch(1,[0, 2, 4, 6, 8]);
    console.log("Correct Answer: 12");
    crunch(3,[0, 1, 10, 11, 20, 21, 22, 30, 32]);
    console.log("Correct Answer: 23");
    crunch(5,[0, 1, 3, 6, 8, 11, 14]);
    console.log("Correct Answer: 3");
    crunch(6,[0, 1, 3, 6, 8, 14, 15, 18, 29, 30, 38, 41, 45, 46, 49, 58, 66, 72, 83, 84]);
    console.log("Correct Answer: 49");
    crunch(2, [0, 21, 31, 45, 49, 54]);
    console.log("Correct Answer: 40");
    crunch(2, [0, 4, 7, 9, 10]);
    console.log("Correct Answer: 7");
    crunch(2, [0, 1, 3, 4, 9]);
    console.log("Correct Answer: 6");
    
    var max = 0;
    var min = Number.POSITIVE_INFINITY;
    var avg = [];
    
    var score = typeof process.argv[2] === 'undefined' ? 60 : process.argv[2];

    for(j = 0; j<10; j++){
        var arr = []; for(let i of cities(score)) arr.push(i);
        var plants = Math.floor(1 + Math.random() * arr.length);
        console.log(`Running: Test:${j} Plants: ${plants}, Cities ${arr.length}, Score: ${score}`);
        // console.log(`City Array: [${arr}]`);
        var t0 = performance.now();
        crunch(plants,arr);
        var t1 = performance.now();
        time = (t1-t0)/1000;
        console.log(`Time Taken = ${time} seconds`);
        avg.push(time);
        max = Math.max(time,max);
        min = Math.min(time,min);
    }
    console.log(`Bench: ${avg.reduce((a,b)=>a+b,0)/avg.length} Max: ${max} Min: ${min} Total: ${avg.reduce((a,b)=>a+b,0)}`);
} else {
    var plants = process.argv[2];
    var arr = process.argv.slice(3);
    console.log(`Running: Plants: ${plants}, Cities ${arr.length}`);
    var t0 = performance.now();
    crunch(plants,arr);
    var t1 = performance.now();
    time = (t1-t0)/1000;
    console.log(`Time Taken = ${time} seconds`);
}

ลองออนไลน์!

ใช้วิธีเดียวกันกับอีกวิธีหนึ่ง

JavaScript (ES6) (Node.js) , คะแนนการทดสอบ = 12

โครงร่างของอัลกอริทึม:

โปรแกรมจะทำการแมปข้อมูลไปที่ระดับเมืองก่อน

  • เมือง - ระยะทางที่แน่นอนของเมือง
  • ซ้าย - ระยะทางของเมืองที่ใกล้ที่สุดไปทางซ้าย
  • ขวา - ระยะทางของเมืองที่ใกล้ที่สุดไปทางขวา
  • ดัชนี - (คัดค้าน) ดัชนีในอาร์เรย์เมืองเดิม

อาร์เรย์จะถูกโยนลงในคลาสกลุ่มซึ่งมีดังต่อไปนี้:

  • เมือง - อาร์เรย์เมือง
  • dist - ระยะทางที่ครอบคลุมกลุ่ม
  • max - การเชื่อมต่อด้านซ้ายที่ใหญ่ที่สุดในกลุ่ม
  • แยก ()
    • ส่งกลับอาร์เรย์ที่มีกลุ่มย่อยแยกไปตามการเชื่อมต่อที่ใหญ่ที่สุดที่เชื่อมต่อกับใจกลางเมืองในกลุ่ม
    • หากมีจุดศูนย์กลาง 2 จุด (กลุ่มความยาวคู่) จะเลือกจากการเชื่อมต่อทั้ง 3 จุด
    • (* หมายเหตุ *: สิ่งนี้จะทำให้กลุ่มใด ๆ ที่มีน้อยกว่าสองเมือง)
  • ศูนย์()
    • ส่งคืนค่า wire ที่ดีที่สุดสำหรับกลุ่ม
    • พยายามหาวิธีแก้ปัญหาเพื่อข้ามการทำซ้ำแต่ละเมืองที่เหลือสำหรับขั้นตอนนี้
    • ขณะนี้มีการทำแผนที่น้อยลง 50%

ตอนนี้อัลกอริทึมดำเนินการแยกกลุ่มตราบใดที่มีโรงไฟฟ้า 2 แห่งขึ้นไป

ในที่สุดมันแมปกลุ่มกับศูนย์กลางของมันและรวมพวกเขาทั้งหมด

วิธีการใช้งาน:

เรียกใช้ Node.js (v9.2.0 เป็นสิ่งที่ใช้สร้าง)

ใช้โปรแกรมโดยใช้กรณีทดสอบที่สร้างขึ้นสำหรับคะแนน 70:

node program.js 70

ใช้โปรแกรมโดยใช้โรงไฟฟ้า 1 แห่งและเมืองต่างๆ [0,3,5]:

node program.js 1 0 3 5

รหัส:

const {performance} = require('perf_hooks');

class City{
	constructor(city, left, right, i){
		this._city = city;
		this._index = i;
		this._left = typeof left === 'undefined' ? 0 : city - left;
		this._right = typeof right === 'undefined' ? 0 : right - city;
	}

	get city(){return this._city;};
	get index(){return this._index;};
	get left(){return this._left;};
    get right(){return this._right;};
    set left(left){this._left = left};
    set right(right){this._right = right};

	valueOf(){return this._left;};
}

class Group{
	constructor(...cities){
        this._cities = cities;
        // console.log(cities.map(a=>a.city).reduce((a,b)=>a===''?a+(b<10?' '+b:b):a+'-'+(b<10?' '+b:b),""));
        // console.log(cities.map(a=>a.left).reduce((a,b)=>a===''?a+(b<10?' '+b:b):a+'-'+(b<10?' '+b:b),""));
        // console.log(cities.map(a=>a.right).reduce((a,b)=>a===''?a+(b<10?' '+b:b):a+'-'+(b<10?' '+b:b),""));
        // console.log("+==+==+==+==+==+==+==+==+==+==+==+==")
		this._dist = cities[cities.length-1].city - cities[0].city;
		this._max = Math.max(...cities); //uses the ValueOf to get the highest Distance to the Left
	}

	get dist(){return this._dist;};
	get cities(){return this._cities;};
	get max(){return this._max;};

	split(){
        //var index = this.cities.findIndex(city=>city.left == this.max);
        //this.cities[index].left = 0;
        // console.log(`Slicing-${this.max}-${index}------`)
        var centerIndex = this.cities.length / 2;
        var splitIndex = Math.floor(centerIndex);
        if(centerIndex%1 > 0){
            var center = this.cities[splitIndex];
            if(center.right > center.left){

                splitIndex++;
            }
        } else {
            var right = this.cities[splitIndex];
            var left = this.cities[splitIndex-1];
            if(left.left > Math.max(right.right,right.left)){
               
                splitIndex--;
            } else if(right.right > Math.max(left.left,left.right)){
                
                splitIndex++;
            }
        }
        // console.log(splitIndex);
        this.cities[splitIndex].left = 0;
        this.cities[splitIndex-1].right = 0;
        var leftCities = [...this.cities.slice(0,splitIndex)];
        var rightCities = [...this.cities.slice(splitIndex)];

        // var center = this.cities[]

        if(leftCities.length <= 1){
            if(rightCities.length <= 1){
                return [];
            }
            return [new Group(...rightCities)]
        }
        if(rightCities.length <= 1){
            return [new Group(...leftCities)];
        }
        return [new Group(...leftCities), new Group(...rightCities)];
	}

    center(){
        if(typeof this._center === 'undefined'){
            if(this.cities.length == 1){
                return [0];
            }
            if(this.cities.length == 2){
                return this.cities[1].left;
            }
            var index = Math.floor(this.cities.length/2);
            this._center = this.cities.reduce((a,b)=> {
                // console.log(`${a} + (${b.city} - ${city.city})`);
                return a + Math.abs(b.city - this.cities[index].city);
            },0);
            // console.log(this._center);
        }
        
        return this._center;
    }

	valueOf(){return this._max;};
}

function crunch(plants, cities){
	var found = [];
    var size = cities.length;
    cities = cities.map((city,i,arr)=> new City(city,arr[i-1],arr[i+1],i));
	var groups = [new Group(...cities)];

	// console.log(groups);
    for(;plants>1;plants--){
        var mapped = groups.map(g=>g.center()-g.max);
        var largest = Math.max(...groups);
        // console.log('Largest:',largest)
        // console.log(...mapped);
		var index = groups.findIndex((g,i)=> mapped[i] == g.center() - g.max && g.max == largest);
		// console.log(index);
        groups = index == 0 ? 
            [...groups[index].split(),...groups.slice(index+1)]:
            [...groups.slice(0,index),...groups[index].split(),...groups.slice(index+1)];
    }
    // console.log(`=Cities=${size}================`);
    // console.log(groups);
    size = groups.map(g=>g.cities.length).reduce((a,b)=>a+b,0);
    
    // console.log(`=Cities=${size}================`);
    var wires = groups.map(g=>g.center());
    
    // console.log(...wires);
    // console.log(`=Cities=${size}================`);
    console.log(`Wire Length Needed: ${wires.reduce((a,b)=>a + b,0)}`);
}

function biggestGroup(groups){
	return groups.find(g => g[g.length-1].orig - g[0].orig);
}

function* range (start, end, limit) {
    while (start < end || typeof limit !== 'undefined' && limit-- > 0) {
        yield start
        start += 1 + Math.floor(Math.random()*100);
    }
}

function* cities (score){
	let n = Math.floor(Math.pow(2,score/5));
	var start = 0;
	while (n-- > 0 && start <= (1000 * n)) {
		yield start;
        start += 1 + Math.floor(Math.random()*100);
    }
}

if(typeof process.argv[3] === 'undefined'){
    crunch(1,[0, 2, 4, 6, 8]);
    console.log("Correct Answer: 12");
    crunch(3,[0, 1, 10, 11, 20, 21, 22, 30, 32]);
    console.log("Correct Answer: 23");
    crunch(5,[0, 1, 3, 6, 8, 11, 14]);
    console.log("Correct Answer: 3");
    crunch(6,[0, 1, 3, 6, 8, 14, 15, 18, 29, 30, 38, 41, 45, 46, 49, 58, 66, 72, 83, 84]);
    console.log("Correct Answer: 49");
    crunch(2, [0, 21, 31, 45, 49, 54]);
    console.log("Correct Answer: 40");
    crunch(2, [0, 4, 7, 9, 10]);
    console.log("Correct Answer: 7");
    
    var max = 0;
    var min = Number.POSITIVE_INFINITY;
    var avg = [];
    
    var score = typeof process.argv[2] === 'undefined' ? 60 : process.argv[2];

    for(j = 0; j<10; j++){
        var arr = []; for(let i of cities(score)) arr.push(i);
        var plants = Math.floor(1 + Math.random() * arr.length);
        console.log(`Running: Test:${j} Plants: ${plants}, Cities ${arr.length}, Score: ${score}`);
        var t0 = performance.now();
        crunch(plants,arr);
        var t1 = performance.now();
        time = (t1-t0)/1000;
        console.log(`Time Taken = ${time} seconds`);
        avg.push(time);
        max = Math.max(time,max);
        min = Math.min(time,min);
    }
    console.log(`Bench: ${avg.reduce((a,b)=>a+b,0)/avg.length} Max: ${max} Min: ${min} Total: ${avg.reduce((a,b)=>a+b,0)}`);
} else {
    var plants = process.argv[2];
    var arr = process.argv.slice(3);
    console.log(`Running: Plants: ${plants}, Cities ${arr.length}`);
    var t0 = performance.now();
    crunch(plants,arr);
    var t1 = performance.now();
    time = (t1-t0)/1000;
    console.log(`Time Taken = ${time} seconds`);
}

ลองออนไลน์!

ฉันจะทำความสะอาดโค้ดที่คอมเม้นท์ในอีกสองสามวันข้างหน้าเนื่องจากฉันยังคงทำงานกับมันอยู่ฉันแค่อยากจะดูว่ามันผ่านไปมากกว่ากรณีเล็ก ๆ หรือไม่


พิจารณา K = 2, A = [0, 21, 31, 45, 49, 54]testcase คำตอบที่ถูกต้องคือ 40 แต่โปรแกรมของคุณส่งออก 51
Colera Su

K = 2, A = [0, 4, 7, 9, 10]ได้ง่าย: ถูกต้อง: 7 คำตอบของคุณ: 8.
Colera Su

โอเคมันควรจะทำงานตอนนี้ ... อย่างน้อยก็ใช้ได้กับทุกกรณี
Wilson Johnson Reta232

จริงๆแล้วฉันอาจได้อัลกอริทึมอื่นที่ใช้งานได้ดีกว่า ฉันจะทดสอบทฤษฎีและโพสต์ไว้เล็กน้อย
Wilson Johnson Reta232

ยังไม่ทำงาน K = 2, A = [0, 1, 3, 4, 9]... ถูกต้อง: 6 คำตอบของคุณ: 7.
Colera Su

1

C (ไม่ใช่การแข่งขัน, คะแนนทดสอบ = 76)

นี่เป็นความพยายามในการแปลโซลูชัน Rust อันดับสองของ @ AndersKaseorg เป็น C

typedef void V;typedef char C;typedef long L;
#define R return
#define W while
#define S static
#include<sys/syscall.h>
#define exit(x)     ({L r;asm volatile("syscall":"=a"(r):"0"(SYS_exit ),"D"(x)              :"cc","rcx","r11","memory");r;})
#define read(x,y,z) ({L r;asm volatile("syscall":"=a"(r):"0"(SYS_read ),"D"(x),"S"(y),"d"(z):"cc","rcx","r11","memory");r;})
#define write(x,y,z)({L r;asm volatile("syscall":"=a"(r):"0"(SYS_write),"D"(x),"S"(y),"d"(z):"cc","rcx","r11","memory");r;})
S V P(L x){C s[32],*p=s+32;*--p='\n';do{*--p='0'+x%10;x/=10;}W(x);write(1,p,s+32-p);}
#define N 0x100000 //max
#define INF (-1ul>>1)
S L cost[N],nk1,*am; //nk1:n-k+1, am:input's partial sums offset with the current "m" in _start()
S L f(L i,L j){if(i+1>=j&&cost[j]!=INF){L h=(i-j+1)>>1;R cost[j]+am[i+1]-am[j+h]-am[i-h+1]+am[j];}else{R INF;}}
S V smawk(L sh,L*c,L nc,L*r){ //sh:shift,c:cols,r:result
 L n=nk1>>sh;if(!n)R;
 L m=n>>1,u[m];
 if(n<nc){
  L ns=0,s[nc],sk[nc],*skp=sk;
  for(L jk=0;jk<nc;jk++){
   L j=c[jk];W(ns>0&&f(~(~(ns-1)<<sh),j)<=f(~(~(ns-1)<<sh),s[ns-1])){--ns;--skp;}
   if(ns<n){s[ns++]=j;*skp++=jk;}
  }
  smawk(sh+1,s,ns,u);for(L i=0;i<m;i++)u[i]=sk[u[i]];
 }else{
  smawk(sh+1,c,nc,u);
 }
 L l=0,ish=(1<<sh)-1,dsh=1<<(sh+1);
 for(L i=0;i<m;i++){
  L k=u[i],bj=l,bc=f(ish,c[l]);
  for(L j=l+1;j<=k;j++){L h=f(ish,c[j]);if(h<bc){bc=h;bj=j;}}
  *r++=bj;*r++=k;l=k;ish+=dsh;
 }
 if(n&1){
  L nsh=~(~(n-1)<<sh),bj=l,bc=f(nsh,c[l]);
  for(L j=l+1;j<nc;j++){L h=f(nsh,c[j]);if(h<bc){bc=h;bj=j;}}
  *r=bj;
 }
}
S L inp(L*a){
 L n=-1,l,v=0;C b[1<<20];
 W(0<(l=read(0,b,sizeof(b))))for(L i=0;i<l;i++)if('0'<=b[i]&&b[i]<='9'){v=b[i]-'0'+10*v;}else{a[++n]=v;v=0;}
 R n;
}
V _start(){
 S L a[N];L n=inp(a),k=*a,s=0;for(L i=0;i<n;i++){a[i]=s;s+=a[i+1];}a[n]=s;
 *cost=0;for(L i=1,l=n+1-k;i<l;i++)cost[i]=INF;
 S L c[N];L nc=n+1-k;for(L i=0;i<nc;i++)c[i]=i;
 S L r[N];nk1=n-k+1;for(L m=0;m<k;m++){am=a+m;smawk(0,c,nc,r);for(L i=n-k;i>=0;i--)cost[i]=f(i,r[i]);}
 P(cost[n-k]);exit(0);
}

รวบรวมกับ:

#!/bin/bash -e
clang -O3 -nostdlib -ffreestanding -fno-unwind-tables -fno-unroll-loops -fomit-frame-pointer -oa a.c
strip -R.comment -R'.note*' a

1

สะอาดคะแนน = 65

module main
import StdEnv, System.IO

parseArgs :: *World -> ((Int, {#Int}), *World)
parseArgs world
    # (args, world)
        = nextArgs [] world
    # args
        = reverse args
    # (k, a)
        = (hd args, tl args)
    = ((toInt k, {toInt n \\ n <- a}), world)
where
    nextArgs :: [String] *World -> ([String], *World)
    nextArgs args world
        # (arg, world)
            = evalIO getLine world
        | arg == ""
            = (args, world)
        = nextArgs [arg:args] world

minimalWeight :: Int !{#Int} -> Int
minimalWeight k a
    # count
        = size a
    # touches
        = createArray ((count - k + 3) / 2 * k) 0
    = treeWalk k count a [(0, 0, 0, 0)] touches
where
    treeWalk :: Int !Int {#Int} ![(!Int, !Int, Int, Int)] *{Int} -> Int
    treeWalk k verticies a [(weight, vertex, degree, requires) : nodes] touches
        | vertex >= verticies
            = weight
        | requires >= k
            = treeWalk k verticies a nodes touches
        # index
            = degree * k + requires
        | (select touches index) > vertex
            = treeWalk k verticies a nodes touches
        # (next, pivot)
            = (vertex + 1 + degree, verticies + requires)
        # (nodes, touches)
            = (orderedPrepend (weight, next, 0, requires + 1) nodes, update touches index (vertex + 1))
        | pivot >= k + next
            # (weight, vertex)
                = (weight + (select a next) - (select a vertex), vertex + 1)
            # nodes
                = orderedPrepend (weight, next + 1, 0, requires + 1) nodes
            | pivot == k + next
                = treeWalk k verticies a nodes touches
            # weight
                = weight + (select a (next + 1)) - (select a vertex)
            # nodes
                = orderedPrepend (weight, vertex, degree + 1, requires) nodes
            = treeWalk k verticies a nodes touches
        = treeWalk k verticies a nodes touches
    where
        orderedPrepend :: (!Int, Int, Int, Int) ![(!Int, Int, Int, Int)] -> [(Int, Int, Int, Int)]
        orderedPrepend a []
            = [a]
        orderedPrepend a [b : b_]
            # (x, _, _, _)
                = a
            # (y, _, _, _)
                = b
            | y > x
                = [a, b : b_]
            = [b : orderedPrepend a b_]

Start world
    # ((k, a), world)
        = parseArgs world
    = minimalWeight k a

รวบรวมกับ:
clm -h 1024M -gci 32M -gcf 32 -s 32M -t -nci -ou -fusion -dynamics -IL Platform main

ใช้เวลาKและจากนั้นองค์ประกอบของแต่ละAเป็นอาร์กิวเมนต์บรรทัดคำสั่ง


@ColeraSu ฉันขอถามสิ่งที่ปัจจัยการตัดสินใจในคะแนน? ความถูกต้อง / เวลา / หน่วยความจำ? ฉันหวังว่ามันเป็นเวลา
2560

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