ผลิตภัณฑ์ Combinatorial เฉพาะช่วงเวลา


21

คำแถลงปัญหา

กำหนดชุดเฉพาะช่วงเวลาที่ต่อเนื่องกัน (ไม่จำเป็นต้องรวม 2) สร้างผลิตภัณฑ์ของการรวมกันของพลังแรกของช่วงเวลาเหล่านี้ - เช่นไม่มีการซ้ำ - และ 1 ตัวอย่างเช่นให้ชุด {2, 3, 5, 7} คุณสร้าง {1, 2, 3, 5, 6, 7, 10, 14, 15, 21, 30, 35, 42, 70, 105, 210} เพราะ:

  1  =  1
  2  =  2
  3  =  3
  5  =  5
  6  =  2 x 3
  7  =  7
 10  =  2 x 5
 14  =  2 x 7
 15  =  3 x 5
 21  =  3 x 7
 30  =  2 x 3 x 5
 35  =  5 x 7
 42  =  2 x 3 x 7
 70  =  2 x 5 x 7
105  =  3 x 5 x 7
210  =  2 x 3 x 5 x 7

โปรดทราบว่าหากความสำคัญของชุดอินพุตของคุณคือ k สิ่งนี้จะให้สมาชิก 2 ^ k ในชุดเอาต์พุตของคุณ

กฎ / เงื่อนไข

  1. คุณสามารถใช้ภาษาใดก็ได้ มีจุดมุ่งหมายเพื่อนับจำนวนตัวอักษรที่เล็กที่สุดของซอร์สโค้ด
  2. โซลูชันของคุณต้องเป็นโปรแกรมที่สมบูรณ์หรือฟังก์ชันที่สมบูรณ์ ฟังก์ชั่นสามารถระบุชื่อได้ (หากภาษาของคุณรองรับฟังก์ชั่นที่ไม่ระบุชื่อ)
  3. โซลูชันของคุณควรสนับสนุนผลิตภัณฑ์อย่างน้อย 2 ^ 31 ไม่ต้องกังวลเกี่ยวกับการตรวจจับหรือจัดการจำนวนเต็มล้นหากคุณส่งผ่านหมายเลขซึ่งผลิตภัณฑ์ดีเกินกว่าที่จะแสดงได้ อย่างไรก็ตามโปรดระบุขีด จำกัด ของการคำนวณของคุณ
  4. คุณอาจยอมรับรายการหรือชุดและสร้างรายการหรือชุด คุณอาจสมมติว่าอินพุตถูกเรียงลำดับ แต่คุณไม่จำเป็นต้องสร้างเอาต์พุตที่เรียงลำดับ

พื้นหลัง

มีประโยชน์เมื่อใดหรือทำไม หนึ่งในสถานที่มันเป็นประโยชน์มากในการสร้างตารางของตัวคูณที่จะแข่งขันในแบบคู่ขนานในขั้นตอนวิธีการจำนวนเต็มแฟรู้จักกันในนามสแควร์ Forms ตัวประกอบ. ที่นั่นแต่ละตัวคูณคี่ที่คุณพยายามลดความน่าจะเป็นของอัลกอริทึมที่ล้มเหลว ดังนั้นด้วยชุดของการสร้างช่วงเวลา {3, 5, 7, 11} ซึ่งสร้างชุดของตัวคูณการทดลอง 16 ตัวเพื่อการแข่งขันแบบขนานอัลกอริทึมจะล้มเหลวประมาณ 2 ^ –16 ของเวลาในการ semiprimes อย่างหนัก การเพิ่ม 13 ลงในรายการ primes สร้างชุดของตัวคูณการทดลอง 32 ชุดซึ่งช่วยลดโอกาสที่จะล้มเหลวได้ประมาณ 2 ^ –32 ทำให้ได้ผลลัพธ์ที่ดีขึ้นอย่างมากโดยไม่มีค่าใช้จ่ายในการคำนวณเพิ่มเติม โดยเฉลี่ยมันยังคงหาคำตอบในจำนวนขั้นตอนเดียวกันทั้งหมด)

คำตอบ:


18

Pure Bash ขนาด 32 ไบต์

eval echo \$[{1,${1// /\}*{1,}}]

อ่านรายการอินพุต (คั่นด้วยเว้นวรรคเดียว) ที่ส่งผ่านเป็น ARG บรรทัดคำสั่ง

ใช้การขยายเชลล์ที่แตกต่างกันสามแบบ:

  1. ${1// /\}*{1,}คือการขยายตัวพารามิเตอร์ว่าช่องว่างแทนที่ใน2 3 5 7ด้วยที่จะให้ }*{1, และจะมีการเพิ่มจุดเริ่มต้นและสิ้นสุดตามลำดับเพื่อให้ เป็นทับขวาหนีเพื่อป้องกันไม่ให้ความพยายามที่จะทำการขยายตัวทางคณิตศาสตร์ในขั้นตอนนี้2}*{1,3}*{1,5}*{1,7\$[{1,}]\$[{1,2}*{1,3}*{1,5}*{1,7}]\$[
  2. \$[{1,2}*{1,3}*{1,5}*{1,7}]เป็นขยายตัวรั้ง เนื่องจากโดยทั่วไปแล้วการขยายรั้งจะเกิดขึ้นก่อนการขยายพารามิเตอร์เราจึงต้องใช้evalเพื่อบังคับให้การขยายพารามิเตอร์เกิดขึ้นก่อน $[1*1*1*1] $[1*1*1*7] $[1*1*5*1] ... $[2*3*5*7]ผลของการขยายตัวรั้งคือ
  3. $[1*1*1*1] $[1*1*1*7] $[1*1*5*1] ... $[2*3*5*7]เป็นรายการของการขยายเลขคณิตซึ่งจะถูกประเมินเพื่อให้รายการหมายเลขที่เราต้องการ

เอาท์พุท:

$ ./comboprime.sh "2 3 5 7"
1 7 5 35 3 21 15 105 2 14 10 70 6 42 30 210
$

3
ใจ ... เป่า ... ว้าว!
ทอดด์เลห์แมน

Wtf ... ฉันได้รับ1 0
username.ak

@ username.ak ข้อมูลที่คุณป้อนคืออะไร คุณจะใส่มันอย่างไร (บรรทัดคำสั่ง args?) คุณใช้ bash เวอร์ชันใดอยู่ bash --version
Digital Trauma

12

CJam, 13 ไบต์

1aq~{1$f*+}/p

อ่านอาร์เรย์ (เช่น[2 3 5 7]) จาก STDIN ลองออนไลน์

ฟังก์ชั่นที่ไม่ระบุชื่อจะมีจำนวนไบต์เดียวกัน:

{1a\{1$f*+}/}

ตัวอย่างการวิ่ง

$ cjam <(echo '1aq~{1$f*+}/p') <<< '[]'
[1]
$ cjam <(echo '1aq~{1$f*+}/p') <<< '[2 3 5 7]'
[1 2 3 6 5 10 15 30 7 14 21 42 35 70 105 210]

มันทำงานอย่างไร

1a               " Push R := [1].              ";
  q~             " Read an array A from STDIN. ";
    {     }/     " For each a ∊ A:             ";
     1$f*+       "     R += { ra : r ∊ R }     ";
            p    " Print.                      ";

4
ว้าวนี่เป็นวิธีที่ชาญฉลาดในการทำซ้ำผ่านชุดย่อยทั้งหมด
Martin Ender

9

Haskell, 22

การแก้ปัญหาคือฟังก์ชั่นที่ไม่ระบุชื่อ:

map product.mapM(:[1])

ตัวอย่างการใช้งาน:

*Main> map product.mapM(:[1]) $ [2,3,5]
[30,6,10,2,15,3,5,1]

คำอธิบาย:
(:[1])เป็นฟังก์ชั่นที่ได้รับหมายเลขที่ส่งกลับรายการx เป็นฟังก์ชั่นที่ให้รายชื่อของตัวเลขจับคู่ฟังก์ชั่นเหล่านั้นและส่งกลับทุกวิธีที่เป็นไปได้ในการเลือกองค์ประกอบจากทุกรายการ ตัวอย่างแรกแผนที่ฟังก์ชั่นที่จะได้รับ แล้วทางเลือกที่เป็นไปได้มีการ(เลือกจำนวนครั้งแรกของทั้งคู่) และเพื่อให้มันกลับ จากนั้นจึงแมปตามตัวเลือกทั้งหมดและส่งคืนผลิตภัณฑ์ซึ่งเป็นผลลัพธ์ที่ต้องการ ฟังก์ชั่นนี้เป็น polymorphic ในประเภทซึ่งหมายความว่ามันสามารถทำงานกับตัวเลขทุกประเภท คุณสามารถป้อนรายการและผลลัพธ์จะเป็นรายการแต่ยังสามารถใช้กับรายการประเภทได้[x,1]
mapM(:[1])(:[1])mapM(:[1]) $ [3,4][[3,1] , [4,1]][3,4][3,1] [1,4][1,1][[3,4],[3,1],[1,4],[1,1]]

map product

IntIntIntegerIntegerและกลับรายการ นี่หมายความว่าพฤติกรรมล้นไม่ได้ถูกระบุโดยฟังก์ชั่นนี้ แต่ตามประเภทของอินพุต (ระบบประเภทที่แสดงออกของ yay Haskell :))


ดี! มีการ จำกัด ขนาดของตัวเลขหรือไม่?
ทอดด์เลห์แมน

1
@ToddLehman ไม่ ประเภทตัวเลขเริ่มต้นคือIntegerซึ่งเป็นประเภทจำนวนเต็มไม่ จำกัด นอกจากนี้ยังIntมีจำนวนเต็ม 32 บิต แต่ส่วนใหญ่เป็นเพียงมรดก
John Dvorak

@JanDvorak ในทางปฏิบัติใช่ แต่ฉันชอบระบบประเภทมากเกินไปที่จะไม่พูดถึงมัน :) อีกสิ่งที่ควรสังเกตคือเพราะมันไม่ระบุตัวตนมันสำคัญกับวิธีที่คุณใช้เพราะข้อ จำกัด monomorphism อาจนำไปใช้ในบางกรณี
ภูมิใจ haskeller

8

Mathematica, 18 17 ไบต์

1##&@@@Subsets@#&

นั่นเป็นฟังก์ชั่นนิรนาม เรียกว่าชอบ

1##&@@@Subsets@#&[{2,3,5,7}]

และมาร์ตินก็ตบท้ายด้วยคำตอบสั้น ๆ อย่างสวยงาม!
ทอดด์เลห์แมน

@ToddLehman ตอนนี้เราจะรอคำตอบ J ที่ดีกว่านี้ ;)
Martin Ender

1
หาก Mathematica ไม่ได้ปิดแหล่งที่มาใครบางคนสามารถเขียนเวอร์ชัน golfed ×@@@𝒫@#ควรจะเอาชนะไม่ได้
เดนนิส

@Dennis ข้อกำหนดของภาษา Wolfram มีให้บริการอย่างอิสระจาก Mathematica และฉันคิดว่ามีการใช้งานโอเพ่นซอร์สหนึ่งหรือสอง (ไม่สมบูรณ์) การสร้าง Mathematica รุ่น Unicode-aliased ได้รับการแนะนำสองสามครั้ง แต่ฉันไม่คิดว่ามันจะได้รับการตอบรับที่ดีบน PPCG ^^
Martin Ender

2
@ MartinBüttnerขอโทษที่ทำให้คุณต้องรอ: (*/@#~2#:@i.@^#)16 ตัวอักษรใน J;)
algorithmshark

4

อัพเดท: C (ฟังก์ชั่น f), 92

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

ฉันเก็บเอาท์พุทเป็น stdout เพราะการตั้งค่าอาร์เรย์จำนวนเต็มและคืนค่ามันจะนานขึ้นแน่นอน

ขอบคุณเดนนิสสำหรับเคล็ดลับ

ดูฟังก์ชั่นf(92 ตัวอักษรยกเว้นช่องว่างที่ไม่จำเป็น) ในโปรแกรมทดสอบด้านล่าง

เอาต์พุตผ่าน printf

j;

f(int c,int*x){
  int p=1,i;
  for(i=c<<c;i--;p=i%c?p:!!printf("%d ",p))p*=(i/c>>i%c)&1?1:x[i%c];
}

main(int d,char**v){
  d--;
  int y[d];
  for(j=d;j--;)y[j]=atoi(v[j+1]);
  f(d,y);
}

เอาต์พุตผ่านตัวชี้อาร์เรย์

j,q[512];

f(int c,int*x,int*p){
    for(int i=-1;++i-(c<<c);p[i/c]*=(i/c>>i%c)&1?1:x[i%c])i%c||(p[i/c]=1);
}

main(int d,char**v){
  d--;
  int y[d];
  for(j=d;j--;)y[j]=atoi(v[j+1]);
  f(d,y,q);
  for(j=1<<d;j--;)printf("%d ",q[j]);
}

C (โปรแกรม), 108

ไม่รวมช่องว่างที่ไม่จำเป็น

p=1,i;
main(int c,char**v){
  c-=1;
  for(i=c<<c;i--;i%c||(printf("%d ",p),p=1))(i/c>>i%c)&1||(p*=atoi(v[i%c+1]));
}

อินพุตจาก commandline เอาต์พุตไปยัง stdout C จะไม่ชนะที่นี่ แต่บางทีฉันอาจลองแปลงเป็นฟังก์ชันในวันพรุ่งนี้

โดยพื้นฐานแล้วเราวนซ้ำทุก1<<cช่วงของการรวมเข้าด้วยกันโดยแต่ละบิตi/cจะเกี่ยวข้องกับการมีอยู่หรือไม่มีความเฉพาะเจาะจงในผลิตภัณฑ์ "วงใน" i%cวิ่งผ่านจำนวนเฉพาะคูณพวกเขาตามค่าของi/c.เมื่อi%cถึง 0 ผลิตภัณฑ์จะถูกส่งออกจากนั้นตั้งค่าเป็น 1 สำหรับการทำซ้ำ "นอก" ต่อไป

อยากรู้อยากเห็นprintf("%d ",p,p=1)ไม่ทำงาน (มันพิมพ์ 1 เสมอ) นี่ไม่ใช่ครั้งแรกที่ฉันได้เห็นพฤติกรรมแปลก ๆ เมื่อมีการใช้ค่าในprintfและได้รับมอบหมายในภายหลังในวงเล็บเดียวกัน เป็นไปได้ว่าในกรณีนี้เครื่องหมายจุลภาคที่สองไม่ได้รับการใช้เป็นตัวคั่นอาร์กิวเมนต์ แต่เป็นตัวดำเนินการ

การใช้

$ ./a 2 3 5 7
1 2 3 6 5 10 15 30 7 14 21 42 35 70 105 210

C ไม่ได้กำหนดลำดับของอาร์กิวเมนต์อย่างเคร่งครัดโดยเฉพาะการเรียกใช้ฟังก์ชัน C จำนวนมากมีการประเมินผลจากขวาไปซ้าย
COTO

จากส่วนที่ 6.5.2.2 ของISO / IEC 9899: TC3 : ลำดับของการประเมินผลของตัวออกแบบฟังก์ชั่น, ข้อโต้แย้งที่เกิดขึ้นจริงและ subexpressions ภายในข้อโต้แย้งที่เกิดขึ้นจริงจะไม่ได้ระบุ [.]ดังนั้นมันขึ้นอยู่กับคอมไพเลอร์ มีการประเมินข้อโต้แย้ง ด้วย-Wsequence-pointหรือ-WallGCC จะบ่น
เดนนิส

1. คุณสามารถเปลี่ยนc-=1เป็นc--หรือใช้งานได้i=--c<<cหากคุณไม่สนใจ UB (ดูเหมือนว่าจะทำงานกับ GCC) 2. การใช้งานทั้งสองอย่าง||สามารถแทนที่ด้วยตัวดำเนินการที่ประกอบไปด้วย: p=i%c?p:!!printf("%d ",p)และp*=(i/c>>i%c)&1?1:atoi(v[i%c+1])
เดนนิส

@Dennis ขอขอบคุณสำหรับคำแนะนำ! ฉันโพสต์ก่อนนอนดังนั้นฉันก็แค่เรียกใช้โปรแกรม c-=1เป็นพื้นฐานการเล่นกอล์ฟที่ฉันไม่ควรพลาด แต่เป็นการแก้ไขข้อผิดพลาดอย่างรวดเร็วเพราะฉันลืมไปว่ามีหนึ่งสายอักขระพิเศษใน argv (ชื่อโปรแกรม) i=..c<<cทำงานบน GCC / cygwin แต่ฉันทิ้งต้นฉบับไว้ โปรแกรมตามที่เป็นอยู่และย้ายไปยังฟังก์ชัน ดังนั้นฉันเพิ่งเรียนรู้ว่าsizeofไม่สามารถใช้งานอาร์เรย์ที่ส่งผ่านเป็นอาร์กิวเมนต์ของฟังก์ชันได้ ฉันได้รวมคำแนะนำของคุณสำหรับผู้ประกอบการที่ประกอบไปด้วยฟังก์ชัน ฉันติดกับเอาต์พุตเพื่อ stdout ตามที่เห็นไม่มีวิธีสั้น ๆ เพื่อส่งกลับอาร์เรย์
เลเวลริเวอร์เซนต์

ใช่อาร์เรย์ที่ส่งผ่านเป็นอาร์กิวเมนต์ของฟังก์ชันจะสลายไปถึงพอยน์เตอร์ - ไม่ใช่เรื่องแปลกใน C ที่จะส่งตัวชี้ไปยังอาร์เรย์ที่ควรมีผลลัพธ์เป็นพารามิเตอร์ฟังก์ชัน คำถามที่บอกว่าคุณสามารถสันนิษฐานได้ว่าผลิตภัณฑ์ที่มีขนาดเล็กกว่า 2 ^ 31 ดังนั้นคุณก็สามารถส่งผ่านอาร์เรย์ขนาด 512
เดนนิส

3

Haskell, 27 ไบต์

นี่เป็นการใช้งาน Haskell ของคำตอบ CJam ของ @ sudo เป็นฟังก์ชันที่ไม่ระบุชื่อ มันจะไม่เอาชนะ Haskell ที่ยอดเยี่ยมของ @proud haskeller แต่ฉันจะวางมันที่นี่ต่อไป

foldr((=<<)(++).map.(*))[1]

คำอธิบาย: foldrใช้ในฟังก์ชันเลขฐานสองค่าและรายการ foldr f v [a,b,c] == f a (f b (f c v))จากนั้นก็จะเข้ามาแทนที่เซลล์แต่ละข้อเสียในรายการโดยการประยุกต์ใช้ฟังก์ชั่นและจุดสิ้นสุดของรายการด้วยค่าเช่นนี้: ค่าของเราเป็นรายการหนึ่งที่มีองค์ประกอบและฟังก์ชั่นไบนารี1 f = (=<<)(++).map.(*)ตอนนี้fจะใช้เวลาจำนวนnทำให้ฟังก์ชั่น(n*)ที่คูณnทำให้จากมันฟังก์ชั่นg = map(n*)ที่ใช้ฟังก์ชั่นที่ทุกองค์ประกอบของรายการและฟีดที่(=<<)(++)ฟังก์ชั่น นี่(++)คือฟังก์ชั่นการต่อข้อมูลและ(=<<)เป็นโมนาดิคผูกซึ่งในกรณีนี้ใช้ใน(++)และgและให้ฟังก์ชันที่ใช้ในรายการg ไปยังสำเนาของมันและเชื่อมทั้งสองเข้าด้วยกัน

กล่าวโดยย่อ: เริ่มต้นด้วย[1]และสำหรับแต่ละหมายเลขnในรายการอินพุตให้คัดลอกรายการปัจจุบันคูณทุกอย่างด้วยnแล้วต่อท้ายรายการนั้นในรายการปัจจุบัน


3

Python: 55 ตัวอักษร

f=lambda l:l and[x*l[0]for x in f(l[1:])]+f(l[1:])or[1]

สร้างผลิตภัณฑ์ซ้ำโดยเลือกที่จะรวมหรือแยกแต่ละหมายเลขในทางกลับกัน


โซลูชันแบบเรียกซ้ำ! เย็น!
ทอดด์เลห์แมน

ฉันคิดว่าคุณสามารถปล่อยพื้นที่หลังจากandถ้าคุณเขียนผลรวมวิธีอื่น ๆ ?
mathmandan

@ Mathmandan Yup ที่ได้ผลขอบคุณ
xnor

3

PARI / GPขนาด 26 ไบต์

v->divisors(factorback(v))

เวอร์ชันที่ยาวขึ้นรวมถึง

v->divisors(prod(i=1,#v,v[i]))

(30 ไบต์) และ

v->divisors(fold((x,y)->x*y,v))

(31 ไบต์)

โปรดทราบว่าหากอินพุตเป็นเมทริกซ์การแยกตัวประกอบแทนที่จะเป็นชุดจะสามารถบันทึก 18 ไบต์โดยใช้divisorsเพียงอย่างเดียว แต่การแปลงชุดเป็นเมทริกซ์การแยกตัวประกอบดูเหมือนจะใช้เวลามากกว่า 18 ไบต์ (ฉันสามารถทำได้ใน 39 ไบต์โดยตรงในรูปแบบv->concat(Mat(v~),Mat(vectorv(#v,i,1)))หรือ 24 ไบต์โดยการคูณและการรับแฟ็กเตอริ่งv->factor(factorback(v))ใครจะทำได้ดีกว่านี้)


2

ปราชญ์ - 36 34

เป็นหลักเช่นเดียวกับวิธีการแก้ปัญหาของ Martin Büttnerถ้าฉันเข้าใจถูกต้อง อย่างที่ฉันพูดถึงมันในความคิดเห็นฉันก็อาจโพสต์มันเป็นคำตอบ

lambda A:map(prod,Combinations(A))

นี่คือฟังก์ชั่นที่ไม่ระบุชื่อซึ่งสามารถเรียกตัวอย่างได้ดังนี้:

(lambda A:map(prod,Combinations(A)))([2,3,5,7])

1
คุณสามารถโกน 2 ไบต์ด้วยการทำให้ฟังก์ชั่นที่ไม่ระบุชื่อ (มันจะได้รับอนุญาตจากคำถาม)
haskeller ความภาคภูมิใจที่

2

J (20)

สิ่งนี้เปิดออกนานกว่าที่ฉันคาดไว้หรือคาดว่าจะยังคง: สั้นกว่าฮาเซล!

*/@:^"1#:@i.@(2&^)@#

การใช้งาน:

    f=:*/@:^"1#:@i.@(2&^)@#
    f 2 3 5 7
1 7 5 35 3 21 15 105 2 14 10 70 6 42 30 210

สิ่งนี้ใช้ได้กับชุดตัวเลขใด ๆ ไม่ใช่เฉพาะเฉพาะช่วงเวลาเท่านั้น นอกจากนี้จำนวนเฉพาะอาจมีขนาดไม่ จำกัด ตราบเท่าที่อาร์เรย์มี postfix x:2 3 5 7x


*/@#~2#:@i.@^#เป็นทางเลือกสำหรับ 14 ไบต์
ไมล์


1

R, 56 ไบต์

r=1;for(i in 1:length(s))r=c(r,apply(combn(s,i),2,prod))

ฉันกำลังพิจารณาว่านี่คือชุด (และรายการ) ฉันแน่ใจว่ามันสามารถทำให้สั้นลงได้ ฉันจะเห็น.


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