ลบบิตและนับ


26

พิจารณาทุก2^nสตริงไบนารีที่แตกต่างกันของความยาวและถือว่าn n > 2คุณได้รับอนุญาตให้ลบb < n/2บิตออกจากสตริงไบนารี่n-bได้อย่างแน่นอน จำนวนสตริงที่แตกต่างกันที่เหลือขึ้นอยู่กับว่าคุณลบบิตใด สมมติว่าเป้าหมายของคุณคือการปล่อยให้สายอักขระที่เหลืออยู่น้อยที่สุดเท่าที่จะเป็นไปได้ความท้าทายนี้คือการเขียนโค้ดเพื่อคำนวณว่าคุณสามารถออกจากหน้าที่การใช้งานnเพียงเล็กน้อย

ตัวอย่างและn=3 b = 1คุณสามารถออกจากเพียงสองสายและ1100

สำหรับn=9และb = 1,2,3,4เรามี70,18,6,2

สำหรับn=8และb = 1,2,3เรามี40,10,4

สำหรับn=7และb = 1,2,3เรามี20,6,2

สำหรับn=6และb = 1,2เรามี12,4

สำหรับn=5และb = 1,2เรามี6,2

สำหรับคำถามนี้ถูกวางโดยเดิมทีผมในปี 2014 ในรูปแบบที่แตกต่างกันในมิสซูรี่

อินพุตและเอาต์พุต

รหัสของคุณควรเป็นจำนวนเต็มnและส่งออกจำนวนเต็มเดียวสำหรับแต่ละค่าbเริ่มต้นb = 0และเพิ่ม

คะแนน

คะแนนของคุณใหญ่ที่สุดnซึ่งรหัสของคุณเสร็จสมบูรณ์b < n/2ภายในไม่กี่นาทีบนพีซีที่ใช้ Linux ของฉัน ในกรณีที่มีการพักเบรคbรหัสที่ใหญ่ที่สุดของคุณจะถูกนำไปสู่nชัยชนะที่ยิ่งใหญ่ที่สุดร่วมกัน ในกรณีที่เสมอกันในเกณฑ์นั้นรหัสที่เร็วที่สุดสำหรับค่าที่ใหญ่ที่สุดnและbตัดสินใจ หากเวลาอยู่ภายในหนึ่งหรือสองวินาทีของกันคำตอบที่โพสต์แรกจะชนะ

ภาษาและห้องสมุด

คุณสามารถใช้ภาษาของห้องสมุดใด ๆ ที่คุณต้องการ เพราะฉันต้องเรียกใช้รหัสของคุณมันจะช่วยถ้ามันฟรี (เหมือนเบียร์) และทำงานใน Linux


ฉันสมมติว่าb > 0มีความต้องการอินพุตเพิ่มเติมหรือไม่ หรือจะn=3และb=0ก็เอาท์พุท2^nเป็นผล?
Kevin Cruijssen

@KevinCruijssen มันควรจะส่งออก2^nแน่นอน
Anush

นอกจากนี้คุณพูดว่าอินพุตเป็นแบบซิงเกิลnและซิงเกิลbแต่คะแนนนั้นใหญ่ที่สุดnซึ่งโค้ดจะเสร็จสมบูรณ์b < n/2ภายในไม่กี่นาที จะดีกว่าไหมถ้ามีอินพุทเดี่ยวnในกรณีนั้นและให้ผลลัพธ์ทั้งหมด0 <= b < n/2ใช่หรือไม่ หรือเราควรจัดให้มีสองโปรแกรม / ฟังก์ชั่น: หนึ่งรับสองอินพุตnและbและหนึ่งรับเฉพาะอินพุตnและผลลัพธ์ผลลัพธ์ทั้งหมดในช่วง0 <= b < n/2?
Kevin Cruijssen

2
ฉันได้ยกระดับการท้าทายของคุณแล้วดังนั้นไม่สามารถทำได้อีกครั้ง :) แม้ว่าฉันจะไม่ทราบวิธีการคำนวณอย่างมีประสิทธิภาพ (อัลกอริทึม O ที่มีประสิทธิภาพเป็นสิ่งที่ฉันไม่ดีเสมอ .. และเป็นหนึ่งในไม่กี่วิชาที่วิทยาลัยไอทีที่ฉันต้องทำซ้ำสองครั้ง) แต่ดูเหมือนว่า ความท้าทายที่น่าสนใจมาก ฉันอยากรู้ว่าคำตอบของผู้คนมาจากไหน
Kevin Cruijssen

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

คำตอบ:


6

Python 2.7 / Gurobi n = 9

วิธีนี้เป็นการใช้ ILP ของ Gurobi อย่างตรงไปตรงมาสำหรับบูลีน Mixed-Integer Problems (MIP)

เคล็ดลับเพียงอย่างเดียวคือการทำให้สมมาตรเป็นส่วนประกอบของ 1 เพื่อลดขนาดของปัญหาลงครึ่งหนึ่ง

การใช้ใบอนุญาต "ฟรี" ของ Gurobi LLC ในเวลา จำกัด นั้นเรา จำกัด ถึง 2000 ข้อ จำกัด แต่การแก้ไข 10 del 1 นั้นดีเกินกว่า 60 วินาทีในการ จำกัด เวลาบนแล็ปท็อปของฉัน

from gurobipy import *
from itertools import combinations

def mincover(n,d):
    bs = pow(2,n-1-d)
    m = Model()
    m.Params.outputFlag = 0
    b = {}
    for i in range(bs):
      b[i] = m.addVar(vtype=GRB.BINARY, name="b%d" % i)
    m.update()
    for row in range(pow(2,n-1)):
      x = {}
      for i in combinations(range(n), n-d):
        v = 0
        for j in range(n-d):
          if row & pow(2,i[j]):
            v += pow(2,j)
        if v >= bs:
          v = 2*bs-1-v
        x[v] = 1
      m.addConstr(quicksum(b[i] for i in x.keys()) >= 1)
    m.setObjective(quicksum(b[i] for i in range(bs) ), GRB.MINIMIZE)
    m.optimize()
    return int(round(2*m.objVal,0))

for n in range(4,10):
    for d in range((n//2)+1):
        print n, d, mincover(n,d)

UPDATE + CORR: 10,2 มีขนาดทางออกที่ดีที่สุด 31 (ดูตัวอย่าง) Gurobi ไม่แสดงวิธีแก้ปัญหาแบบสมมาตรที่มีขนาด 30 อยู่ (ส่งคืนปัญหาที่เป็นไปไม่ได้) .. [ความพยายามของฉันในการแสดงความเป็นไปได้แบบไม่สมมาตร รูปแบบของจำนวนเต็ม0 7 13 14 25 28 35 36 49 56 63 64 95 106 118 128 147 159 170 182 195 196 200 207 225 231 240 243 249 252 255หรือ0 7 13 14 19 25 28 35 36 49 56 63 64 95 106 118 128 159 170 182 195 196 200 207 225 231 240 243 249 252 255


คุณทำลายสถิติ "การอ้างสิทธิ์ที่ไม่มีที่สิ้นสุดเร็วที่สุด" หรือ
user202729

ฉันไม่เห็นความโปรดปรานใด ๆ ที่นี่คุณหมายถึงอะไร
jayprich

@ user202729 ใช่ .. ฉันตั้งไว้ต่ำเกินไป ฉันควรจะได้ตั้งไว้ที่ n = 10 :)
Anush

การแก้ปัญหาที่ n = 9 ไม่ใช่เรื่องง่าย นั่นเป็นสาเหตุที่ OP ใช้ห้องสมุดที่มีอยู่ (ซึ่งควรจะดีกว่าโซลูชันที่เขียนด้วยมือเช่นของฉัน)
user202729

1
ขอบคุณ @ChristianSievers ฉันเห็น MO อ้างว่า 10,2 มี optima แบบอสมมาตรเท่านั้นซึ่งฉันไม่สามารถปฏิเสธหรือตรวจสอบได้ หากฉันลบทางลัดของสมมติฐานสมมาตรซึ่งใช้งานได้ถึง n = 9 ปรากฎว่า Gurobi ยังคงสามารถแก้ปัญหาได้ถึง n = 9 ในเวลาที่ต้องการ
jayprich

3

C ++, n = 6

กำลังดุร้ายกับการเพิ่มประสิทธิภาพเล็กน้อย

#include<cassert>
#include<iostream>
#include<vector>

// ===========
/** Helper struct to print binary representation.
`std::cout<<bin(str,len)` prints (str:len) == the bitstring 
represented by last (len) bits of (str).
*/
struct bin{
    int str,len;
    bin(int str,int len):str(str),len(len){}
};
std::ostream& operator<<(std::ostream& str,bin a){
    if(a.len)
        return str<<bin(a.str>>1,a.len-1)<<char('0'+(a.str&1));
    else if(a.str)
        return str<<"...";
    else
        return str;
}
// ===========

/// A patten of (len) bits of ones.
int constexpr pat1(int len){
    return (1<<len)-1;
}

// TODO benchmark: make (res) global variable?

/**Append all distinct (subseqs+(sfx:sfxlen)) of (str:len) 
with length (sublen) to (res).
*/
void subseqs_(
    int str,int len,int sublen,
    int sfx,int sfxlen,
    std::vector<int>& res
){
    // std::cout<<"subseqs_ : str = "<<bin(str,len)<<", "
    // "sublen = "<<sublen<<", sfx = "<<bin(sfx,sfxlen)<<'\n';

    assert(len>=0);

    if(sublen==0){ // todo remove some branches can improve perf?
        res.push_back(sfx);
        return;
    }else if(sublen==len){
        res.push_back(str<<sfxlen|sfx);
        return;
    }else if(sublen>len){
        return;
    }

    if(str==0){
        res.push_back(sfx);
        return;
    }

    int nTrail0=0;
    for(int ncut;str&&nTrail0<sublen;

        ++nTrail0,
        ncut=__builtin_ctz(~str)+1, // cut away a bit'0' of str
        // plus some '1' bits
        str>>=ncut,
        len-=ncut
    ){
        ncut=__builtin_ctz(str)+1; // cut away a bit'1' of str
        subseqs_(str>>ncut,len-ncut,sublen-nTrail0-1,
            sfx|1<<(sfxlen+nTrail0),sfxlen+nTrail0+1,
            res
        ); // (sublen+sfxlen) is const. TODO global var?
    }

    if(nTrail0+len>=sublen) // this cannot happen if len<0
        res.push_back(sfx);
}

std::vector<int> subseqs(int str,int len,int sublen){
    assert(sublen<=len);
    std::vector<int> res;
    if(__builtin_popcount(str)*2>len){ // too many '1's, flip [todo benchmark]
        subseqs_(pat1(len)^str,len,sublen,0,0,res);
        int const p1sublen=pat1(sublen);
        for(int& r:res)r^=p1sublen;
    }else{
        subseqs_(str,len,sublen,0,0,res);
    }
    return res;
}

// ==========

/** Append all distinct (supersequences+(sfx:sfxlen)) of (str:len)
with length (suplen) to (res).
Define (a) to be a "supersequence" of (b) iff (b) is a subsequence of (a).
*/
void supseqs_(
    int str,int len,int suplen,
    int sfx,int sfxlen,
    std::vector<int>& res
){
    assert(suplen>=len);

    if(suplen==0){
        res.push_back(sfx);
        return;
    }else if(suplen==len){
        res.push_back(str<<sfxlen|sfx);
        return;
    }

    int nTrail0; // of (str)
    if(str==0){
        res.push_back(sfx);
        // it's possible that the supersequence is '0000..00'
        nTrail0=len;
    }else{
        // str != 0 -> str contains a '1' bit ->
        // supersequence cannot be '0000..00'
        nTrail0=__builtin_ctz(str);
    }
    // todo try `nTrail0=__builtin_ctz(str|1<<len)`, eliminates a branch
    // and conditional statement

    for(int nsupTrail0=0;nsupTrail0<nTrail0;++nsupTrail0){
        // (nsupTrail0+1) last bits of supersequence matches with 
        // nsupTrail0 last bits of str.
        supseqs_(str>>nsupTrail0,len-nsupTrail0,suplen-1-nsupTrail0,
            sfx|1<<(nsupTrail0+sfxlen),sfxlen+nsupTrail0+1,
            res);
    }

    int const strMatch=str?nTrail0+1:len; 
    // either '1000..00' or (in case str is '0000..00') the whole (str)

    for(int nsupTrail0=suplen+strMatch-len;nsupTrail0-->nTrail0;){
        // because (len-strMatch)<=(suplen-1-nsupTrail0),
        // (nsupTrail0<suplen+strMatch-len).

        // (nsupTrail0+1) last bits of supersequence matches with
        // (strMatch) last bits of str.
        supseqs_(str>>strMatch,len-strMatch,suplen-1-nsupTrail0,
            sfx|1<<(nsupTrail0+sfxlen),sfxlen+nsupTrail0+1,
            res);
    }

    // todo try pulling constants out of loops
}

// ==========

int n,b;
std::vector<char> done;
unsigned min_undone=0;

int result;
void backtrack(int nchoice){
    assert(!done[min_undone]);
    ++nchoice;
    std::vector<int> supers_s;
    for(int s:subseqs(min_undone,n,n-b)){
        // obviously (s) is not chosen. Try choosing (s)
        supers_s.clear();
        supseqs_(s,n-b,n,0,0,supers_s);
        for(unsigned i=0;i<supers_s.size();){
            int& x=supers_s[i];
            if(!done[x]){
                done[x]=true;
                ++i;
            }else{
                x=supers_s.back();
                supers_s.pop_back();
            }
        }

        unsigned old_min_undone=min_undone;
        while(true){
            if(min_undone==done.size()){
                // found !!!!
                result=std::min(result,nchoice);
                goto label1;
            }
            if(not done[min_undone])
                break;
            ++min_undone;
        }
        if(nchoice==result){
            // backtrack more will only give worse result
            goto label1;
        }

        // note that nchoice is already incremented
        backtrack(nchoice);

        label1: // undoes the effect of (above)
        for(int x:supers_s)
            done[x]=false;
        min_undone=old_min_undone;
    }
}

int main(){
    std::cin>>n>>b;

    done.resize(1<<n,0);
    result=1<<(n-b); // the actual result must be less than that

    backtrack(0);
    std::cout<<result<<'\n';
}

ทำงานในพื้นที่:

[user202729@archlinux golf]$ g++ -std=c++17 -O2 delbits.cpp -o delbits
[user202729@archlinux golf]$ time for i in $(seq 1 3); do ./delbits <<< "6 $i"; done
12
4
2

real    0m0.567s
user    0m0.562s
sys     0m0.003s
[user202729@archlinux golf]$ time ./delbits <<< '7 1'
^C

real    4m7.928s
user    4m7.388s
sys     0m0.173s
[user202729@archlinux golf]$ time for i in $(seq 2 3); do ./delbits <<< "7 $i"; done
6
2

real    0m0.040s
user    0m0.031s
sys     0m0.009s

1
ส่วนใหญ่เป็นการกระตุ้นให้ผู้อื่นโพสต์รหัสหากเร็วกว่าของฉัน
user202729

กรุณา? ... (หมายเหตุ: นี่เป็นตัวอย่างของปัญหาการตั้งค่า)
user202729

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