การสร้างชุดค่าผสมจากชุดคู่โดยไม่มีการทำซ้ำองค์ประกอบ


28

ฉันมีชุดของคู่ แต่ละคู่เป็นรูปแบบ (x, y) เช่นว่า x, y [0,n)เป็นจำนวนเต็มจากช่วง

ดังนั้นถ้า n คือ 4 ดังนั้นฉันมีคู่ต่อไปนี้:

(0,1) (0,2) (0,3)
(1,2) (1,3) 
(2,3) 

ฉันมีคู่แล้ว ตอนนี้ฉันต้องสร้างชุดค่าผสมโดยใช้n/2คู่ที่ไม่มีจำนวนเต็มซ้ำ (กล่าวอีกอย่างหนึ่งว่าจำนวนเต็มแต่ละค่าปรากฏอย่างน้อยหนึ่งครั้งในชุดค่าผสมสุดท้าย) ต่อไปนี้เป็นตัวอย่างของชุดค่าผสมที่ถูกต้องและไม่ถูกต้องเพื่อความเข้าใจที่ดีขึ้น

 1. (0,1)(1,2) [Invalid as 3 does not occur anywhere]
 2. (0,2)(1,3) [Correct]
 3. (1,3)(0,2) [Same as 2]

มีคนแนะนำฉันถึงวิธีในการสร้างชุดค่าผสมที่เป็นไปได้ทั้งหมดเมื่อฉันมีคู่


บางทีอาจใช้อาร์เรย์ 2d เพื่อเป็นตัวแทนคู่ของคุณ ชุดค่าผสมที่ถูกต้องสอดคล้องกับการเลือกเซลล์อาร์เรย์ n เซลล์ที่แต่ละแถวและคอลัมน์มีเซลล์ที่เลือก 1 เซลล์
Joe

4
คุณกำลังบอกว่าอินพุตเป็นชุดของคู่ทั้งหมดหรือไม่ ถ้าเป็นเช่นนั้นแล้วคุณก็ควรจะพูดว่าใส่เป็นเพียงnn
rgrig

2
เป็นเสมอยัง? หากไม่เป็นเช่นนั้นคำสั่ง "ไม่มีจำนวนเต็มซ้ำ" และ "จำนวนเต็มแต่ละรายการปรากฏอย่างน้อยหนึ่งครั้งในชุดค่าผสมสุดท้าย" จะขัดแย้งกัน n
Dmytro Korduban

1
ปัญหาเดียวกับ @rgrig: อินพุตทั้งหมดไม่มีการเรียงลำดับคู่หรือเป็นชุดของคู่ที่เป็นไปได้โดยพลการหรือไม่ ถ้าเป็นคู่ทั้งหมดคุณก็สามารถบอกได้ว่าอินพุตคือไม่จำเป็นต้องให้รายการ n
Kaveh

1
คุณมีความสนใจในการสร้างการจับคู่ที่สมบูรณ์แบบของกราฟบนจุดกำหนดโดยคู่เริ่มต้นของคุณ ยิ่งกว่านั้นดูเหมือนว่าคุณจะใช้กราฟนั้นเป็นกราฟที่สมบูรณ์ในจุดเหล่านั้น คำถามของคุณจะชัดเจนขึ้นหากคุณพูดถึงเรื่องนั้น มีจับคู่ดังกล่าว ( n - 1 ) ! ! : = 1 × 3 × 5 × × ( n - 1 )n(n1)!!:=1×3×5××(n1)
Marc van Leeuwen

คำตอบ:


14

วิธีการหนึ่งที่ตรงคือขั้นตอนแบบเรียกซ้ำที่ทำต่อไปนี้ในแต่ละการร้องขอ อินพุตไปยังโพรซีเดอร์คือรายการของคู่ที่ถูกเลือกไว้แล้วและรายการของคู่ทั้งหมด

  1. คำนวณจำนวนที่น้อยที่สุดซึ่งไม่ได้กล่าวถึงในรายการอินพุต สำหรับการขอร้องครั้งแรกนี้จะเป็น 0 แน่นอนเพราะไม่มีการเลือกคู่
  2. หากมีการครอบคลุมตัวเลขทั้งหมดคุณมีชุดค่าผสมที่ถูกต้องพิมพ์ออกมาและส่งกลับขั้นตอนก่อนหน้า มิฉะนั้นจำนวนที่น้อยที่สุดที่ไม่ถูกค้นพบคือเป้าหมายที่เราจะตั้งเป้าหมายไว้
  3. ค้นหาผ่านคู่ที่กำลังมองหาวิธีที่จะครอบคลุมจำนวนเป้าหมาย หากไม่มีเลยให้กลับไปที่ระดับการเรียกซ้ำก่อนหน้านี้
  4. หากมีวิธีที่จะครอบคลุมหมายเลขเป้าหมายให้เลือกวิธีแรกและเรียกขั้นตอนทั้งหมดซ้ำอีกครั้งด้วยการเลือกคู่เพิ่มเข้าไปในรายการคู่ที่เลือก
  5. เมื่อมันกลับมาให้มองหาวิธีถัดไปเพื่อให้ครอบคลุมหมายเลขเป้าหมายด้วยคู่โดยไม่ทับซ้อนคู่ที่เลือกไว้ก่อนหน้านี้ หากคุณพบหนึ่งให้เลือกและเรียกซ้ำขั้นตอนต่อไปซ้ำ
  6. ดำเนินการขั้นตอนที่ 4 และ 5 ต่อไปจนกว่าจะไม่มีวิธีครอบคลุมจำนวนเป้าหมาย ผ่านรายการทั้งหมดของคู่ เมื่อไม่มีตัวเลือกที่ถูกต้องให้กลับไปที่ระดับก่อนหน้าของการสอบถามซ้ำ

วิธีการมองเห็นอัลกอริธึมนี้คือต้นไม้ที่มีเส้นทางเป็นลำดับของคู่ที่ไม่ทับซ้อนกัน ระดับแรกของต้นไม้มีคู่ทั้งหมดที่มี 0 สำหรับตัวอย่างข้างต้นต้นไม้คือ

           ราก
             |
     ----------------
     | | |
   (0,1) (0,2) (0,3)
     | | |
   (2,3) (1,3) (1,2)

ในตัวอย่างนี้เส้นทางทั้งหมดผ่านต้นไม้ให้คอลเลกชันที่ถูกต้องจริง แต่ตัวอย่างเช่นถ้าเราออกจากคู่ (1,2) แล้วเส้นทางขวาสุดจะมีเพียงหนึ่งโหนดและจะสอดคล้องกับการค้นหาในขั้นตอนที่ 3 ล้มเหลว

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


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

sub cover {
  i = 0;
  while ( (i < n) && (covered[i] == 1 )) {
   i++;
  }
  if ( i == n ) { print list; return;}
  covered[i] = 1;
  for ( j = 0; j < n; j++ ) {
    if ( covered[j] == 0 ) {
      covered[j] = 1;
      push list, [i,j];
      cover();
      pop list;
      covered[j] = 0;
    }
  }
  covered[i] = 0;
}

สิ่งนี้ควรใช้งานได้ แต่อาจไม่ใช่วิธีที่มีประสิทธิภาพที่สุดในการทำเช่นนั้น
Joe

2
ในท้ายที่สุดประเด็นก็คือการระบุเส้นทางของต้นไม้นั้น หากจำนวนคู่ในรายการอินพุตมีขนาดเล็กกว่าจำนวนคู่ที่เป็นไปได้อัลกอริธึมประเภทนี้จะมีประสิทธิภาพอย่างสมบูรณ์แบบโดยเฉพาะอย่างยิ่งหากมีการใช้ตารางแฮชบางตารางเพื่อช่วยให้จำได้ว่าตัวเลขใดถูกครอบคลุมในแต่ละขั้นตอน สามารถสอบถามได้ในเวลาคงที่
Carl Mummert

หากรายการนั้นใช้พอยน์เตอร์แล้วDancing Dancing ของ Knuthก็คุ้มค่าที่จะดู เมื่อคุณกลับฟอร์มเรียกซ้ำและต้องเรียกคืนสถานะก่อนหน้าของรายการ
uli

10

คุณสามารถแก้มันซ้ำแล้วซ้ำอีก สมมติว่าคุณมีการแก้ปัญหาทั้งหมดสำหรับช่วงn) จากนั้นคุณสามารถสร้างโซลูชันจากได้อย่างง่ายดาย ขนาดจะเติบโตอย่างรวดเร็วด้วยดังนั้นจึงควรเขียนตัวสร้างแทนที่จะเก็บชุดทั้งหมดในหน่วยความจำดูตัวอย่าง Python ด้านล่าง [ 0 , n ) S n + 2 S n nSn[0,n)Sn+2Snn

def pairs(n):
    if (n%2==1 or n<2):
        print("no solution")
        return
    if (n==2):
        yield(  [[0,1]]  )
    else:
        Sn_2 = pairs(n-2) 
        for s in Sn_2:
            yield( s + [[n-2,n-1]] )
            for i in range(n/2-1):
                sn = list(s)
                sn.remove(s[i])
                yield( sn + [ [s[i][0], n-2] , [s[i][1], n-1] ] )
                yield( sn + [ [s[i][1], n-2] , [s[i][0], n-1] ] )

คุณสามารถแสดงรายการทุกคู่โดยโทร

for x in pairs(6):
   print(x)

6

ปรับปรุง : คำตอบก่อนหน้าของฉันจัดการกับกราฟสองฝ่ายซึ่ง OP ไม่ได้ถาม ฉันจะทิ้งไว้ในตอนนี้เพื่อเป็นข้อมูลที่เกี่ยวข้อง แต่ข้อมูลที่เกี่ยวข้องมากขึ้นเกี่ยวข้องกับการจับคู่ที่สมบูรณ์แบบในกราฟ nonbipartite

ในเรื่องนี้มีการสำรวจที่ดีโดย Proppที่แสดงความคืบหน้า (จนถึงปี 1999) แนวคิดบางอย่างในบทความนั้นและลิงก์ที่เกี่ยวข้องอาจพิสูจน์ว่ามีประโยชน์ TL; DR คือ - มันช่างยาก :)

--- เริ่มจากคำตอบเก่า ๆ

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

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


กราฟสองส่วนประกอบด้วยสองชุดที่มีป้ายกำกับที่ระบุ [0, n) และมีขอบ (i, j) ถ้าหาก (i! = j)
Joe

ฉันไม่คิดว่าคุณจะต้องใส่โหนดสำหรับคู่เราสามารถรักษาพวกเขาเป็นขอบ กล่าวอีกนัยหนึ่งเรามีกราฟที่สมบูรณ์ในจุดยอดและเราต้องการสร้างจุดยอดทั้งหมด ดังนั้นจึงดูเหมือนว่าผมว่าปัญหาได้รับการคำนวณถาวรของK_nK nnKn
Kaveh

2
ถาวรคำนวณคำตอบ แต่ OP ต้องการแจกแจงพวกเขา
Suresh

พวกเขาทั้งหมด isomorphic เนื่องจากโครงสร้างกราฟดังนั้นการคิดเกี่ยวกับการเรียงสับเปลี่ยนอาจเป็นความคิดที่ดี (แต่ปัญหาคือมันจะสร้างรายการซ้ำ)
Kaveh

4

ทุกคู่ที่คุณเลือกกำจัดสองแถวที่คุณไม่สามารถเลือกได้อีกต่อไป แนวคิดนี้สามารถใช้ในการตั้งค่าอัลกอริทึมแบบเรียกซ้ำ (ใน Scala):

def combine(pairs : Seq[(Int,Int)]) : Seq[Seq[(Int, Int)]] = pairs match {
  case Seq() => Seq()
  case Seq(p) => Seq(Seq(p))
  case _ => {
    val combinations = pairs map { case (a,b) => {
      val others = combine(pairs filter { case (c,d) =>
        a != c && a != d && b != c && b != d
      })

      others map { s => ((a,b) +: s) }
    }}

    combinations.flatten map { _.sorted } distinct
  }
}

สิ่งนี้สามารถแสดงออกได้อย่างมีประสิทธิภาพมากขึ้น filterโดยเฉพาะอย่างยิ่งความคิดของการไม่ต้องพิจารณาแถวทั้งชุดจะไม่ใช้การเรียกร้องให้


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

n2N

(0,1)n=4

ใช่. แต่อย่างที่ฉันพูดคำตอบของฉันเกี่ยวกับสถานการณ์ที่ OP เสนอคือไม่ใช่อินพุตโดยพลการ
Raphael

เมื่อฉันอ่านคำถามดั้งเดิมมันเกี่ยวกับชุดของคู่โดยพลการ OP ไม่เคยบอกว่าเป็นไปได้ทั้งหมด แต่ฉันเห็นด้วยกับ OP อาจชัดเจนเกี่ยวกับเรื่องนั้นมากกว่า
Carl Mummert

4

ในขณะที่มีคำตอบที่น่ารักมากมายสำหรับคำถามนี้ฉันคิดว่ามันเป็นการดีที่จะชี้ให้เห็นถึงเคล็ดลับพื้นฐานทั่วไปที่อยู่เบื้องหลังพวกเขา

มันง่ายกว่ามากในการสร้างชุดค่าผสมที่ไม่ซ้ำกันถ้าคุณสามารถรวมองค์ประกอบทั้งหมด วิธีนี้รับประกันความเป็นเอกลักษณ์หากเราอนุญาตเฉพาะชุดค่าผสมที่เรียงลำดับเท่านั้น มันไม่ยากที่จะสร้างชุดค่าผสมที่เรียงกัน - เพียงแค่ทำการค้นหาการแจงนับกำลังตามปกติ แต่ในแต่ละขั้นตอนจะเลือกองค์ประกอบที่มีขนาดใหญ่กว่าเท่านั้น

ภาวะแทรกซ้อนพิเศษในปัญหานี้คือความปรารถนาที่จะได้รับการรวมกันของความยาว n / 2 (ความยาวสูงสุด) นี่ไม่ใช่เรื่องยากที่จะทำถ้าเราตัดสินใจเลือกกลยุทธ์ที่ดี ตัวอย่างเช่นตามที่ระบุไว้ในคำตอบของ Carl Mummet หากเราพิจารณาเรียงลำดับพจนานุกรม (จากบนลงล่างซ้ายขวาในแผนภาพในคำถาม) เราได้รับกลยุทธ์ในการรับองค์ประกอบถัดไปเสมอเพื่อให้ตัวเลขแรกเป็น จำนวนที่น้อยที่สุดยังไม่ได้ใช้

เราสามารถขยายกลยุทธ์นี้หากเราต้องการสร้างลำดับของความยาวอื่น ๆ เพียงจำไว้ว่าเมื่อใดก็ตามที่เราเลือกองค์ประกอบถัดไปที่มีหมายเลขแรกไม่ใช่เลขที่เล็กที่สุดที่มีอยู่เราจะแยกแยะองค์ประกอบหนึ่งหรือหลายแถวออกจากที่ปรากฏในการเรียงลำดับดังนั้นความยาวสูงสุดของการประกาศจะลดลงตามลำดับ


3

ฉันไม่แน่ใจว่านี่คือสิ่งที่คุณถาม แต่อย่างที่ฉันเข้าใจคุณมีทั้งหมด selectคู่ที่ไม่เรียงลำดับของและต้องการนับรายการของคู่ทั้งหมดที่ ครอบคลุมชุดโดยที่คือเลขคู่ เราสามารถคิดว่านี้เป็นขอบปูของกราฟที่สมบูรณ์แบบบนจุด [n]={1,,n}[n]nKnn(n2)[n]={1,,n}[n]nKnn

ยิ่งไปกว่านั้นคำถามดูเหมือนว่าจะถือว่าตัวเลขแต่ละตัวในปรากฏเพียงครั้งเดียวในรายการ ซึ่งในกรณีนี้เราเป็นเพียงการมองหาที่ปูที่มีการจับคู่ที่สมบูรณ์แบบ จำนวนของการจับคู่ในกราฟคือเท่ากับถาวรของเมทริกซ์ถ้อยคำ ดังนั้นเราจึงต้องคำนวณ(K_n)P e r m ( K n )[n]Perm(Kn)

เป็นที่ทราบกันว่าถาวรคือแต่นี่เป็นกรณีทั่วไป สำหรับมีรายการดังกล่าว #P-complete n !Knn!2n2

วิธีที่ง่ายที่สุดในการสร้างสิ่งเหล่านี้คือการแก้ไขการจับคู่ที่สมบูรณ์แบบและจากนั้นใช้การเปลี่ยนแปลงของแต่สิ่งนี้จะทำให้เกิดการซ้ำซ้อนมากมาย[n]

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