Elementlerin tekrarı olmadan bir çift setinden kombinasyon oluşturma


28

Bir çift çiftim var. Her çift, (x, y) formundadır, öyle ki, x, y, aralıktaki tam sayılara aittir [0,n).

Yani, n 4 ise, o zaman aşağıdaki çiftleri var:

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

Zaten çiftlerim var. Şimdi, n/2tamsayıların hiçbirinin tekrarlanmayacağı şekilde çiftler kullanarak bir kombinasyon oluşturmam gerekiyor (başka bir deyişle, her bir tamsayı son kombinasyonda en az bir kez belirir). Aşağıda daha iyi anlaşılması için doğru ve yanlış kombinasyon örnekleri verilmiştir.

 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]

Birisi bana çiftleri aldığımda tüm olası kombinasyonları oluşturmanın bir yolunu önerebilir mi?


Belki de çiftlerinizi temsil etmek için bir 2d dizisi kullanarak. Geçerli kombinasyonlar, her bir sıra ve sütun tam olarak seçilen 1 hücre içerecek şekilde n dizi hücrelerinin seçimine karşılık gelir.
Joe

4
Girişin tüm çiftlerin kümesi olduğunu mu söylüyorsunuz ? Öyleyse, girişin sadece olduğunu söylemelisiniz . n
rgrig

2
Is bile her zaman? Aksi halde, "tam sayıların hiçbiri tekrar edilmez" ifadeleri ve "her bir tam sayı, en son kombinasyonda en az bir kez görünür" ifadeleri çelişkilidir. n
Dmytro Korduban

1
@rgrig ile aynı problem: giriş, tüm sıralanmamış çiftler mi, yoksa isteğe bağlı olası çiftler kümesi mi? Hepsi çiftse o zaman girişin olduğunu söyleyebilirsiniz , listeyi vermeye gerek yoktur. n
Kaveh

1
Grafiğin tüm mükemmel eşleşmelerini başlangıçtaki çiftler kümeniz tarafından tanımlanan noktalarında oluşturmakla ilgileniyorsunuz . Üstelik, o grafiği o noktalardaki tam grafik olarak alıyorsunuz. Bundan bahsetseniz, sorunuz daha net olurdu. Var ( n - 1 ) ! ! : = 1 × 3 × 5 × × ( n - 1 ) bu eşleşmeler. n(n1)!!:=1×3×5××(n1)
Marc van Leeuwen

Yanıtlar:


14

Doğrudan bir yol, her başvuruda aşağıdakileri yapan özyinelemeli bir prosedürdür. Prosedürün girişi, daha önce seçilmiş olan çiftlerin ve tüm çiftlerin bir listesidir.

  1. Giriş listesi tarafından kapsanmayan en küçük sayıyı hesaplayın. İlk çağrı için, elbette 0 olacaktır, çünkü hiçbir çift seçilmedi.
  2. Tüm numaralar kaplanmışsa, doğru bir kombinasyonunuz vardır, yazdırın ve önceki adıma geri dönün. Aksi halde, ele geçen en küçük sayı hedefleyeceğimiz hedeftir.
  3. Hedef numarayı kapsayacak bir yol arayan çiftleri arayın. Eğer yoksa, o zaman önceki özyinelemeye geri dönün.
  4. Hedef numarayı gizlemenin bir yolu varsa, ilk yolu seçin ve tekrar tekrar tüm işlemi tekrar arayın, seçilen çiftler seçilen çiftlerin listesine eklenir.
  5. Bu geri döndüğünde, daha önce seçilen bir çifti üst üste binmeden hedef numarayı bir çift ile örtmek için bir sonraki yolu arayın . Bir tane bulursanız, onu seçin ve tekrarlı olarak bir sonraki prosedürü çağırın.
  6. Hedef numarayı kapatacak başka yol bulunmayana kadar 4. ve 5. adımlara devam edin. Tüm çiftlerin listesine göz atın. Başka doğru seçenek olmadığında, önceki özyinelemeye geri dönün.

Bu algoritmayı görselleştirmenin yolu, yolları örtüşmeyen çiftlerin dizileri olan bir ağaçtır. Ağacın ilk seviyesi, 0 içeren tüm çiftleri içerir. Yukarıdaki örnekte, ağaç

           Kök
             |
     ----------------
     | | |
   (0,1) (0,2) (0,3)
     | | |
   (2,3) (1,3) (1,2)

Bu örnekte, ağaçtaki tüm yollar aslında doğru koleksiyonlar verir, ancak örneğin çifti (1,2) dışarıda bırakırsak, en sağdaki yol yalnızca bir düğüme sahip olur ve 3. adımdaki aramaya karşılık gelir.

Bu tür arama algoritmaları, belirli bir türdeki tüm nesneleri numaralandırmada benzer birçok problem için geliştirilebilir.


Belki de OP’nin tüm çiftlerin girişte olduğu, sadece sorunun söylediği gibi bir dizi anlamına geldiği öne sürülmüştür . Bu durumda algoritma çok daha kolaydır çünkü hangi çiftlere izin verildiğini kontrol etmek artık gerekli değil. Tüm çiftlerin setini oluşturmak bile gerekli değildir; Aşağıdaki sözde kod OP'nin istediğini yapacaktır. Burada giriş numarasıdır, "liste" boş bir liste olarak başlar ve "örtülü" 0 ile başlayan n uzunluğundaki bir dizidir. Biraz daha verimli yapılabilir ama bu benim asıl amacım değil.nn

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

Bu çalışması gerekir, ancak muhtemelen bunu yapmanın en etkili yolu değildir.
Joe

2
Sonunda, nokta bir şekilde o ağacın yollarını numaralandırmaktır. Giriş listesindeki çiftlerin sayısı, olası çiftlerin sayısından çok daha küçükse, bu tür bir algoritma, özellikle her adımda hangi sayıların zaten kapsandığını hatırlamaya yardımcı olmak için bazı karma tablolar kullanılıyorsa, mükemmel verimli olacaktır. bu sabit sürede sorgulanabilir.
Carl Mummert

Listede işaretçiler kullanılıyorsa, Knuth'un Dans Bağlantıları bakmaya değer. Döndüğünüzde özyinelemeli bir arama yapın ve listenin önceki durumunu geri yüklemek zorundasınız.
Uli

10

Yinelemeli olarak çözebilirsin. Tüm çözümlerin olduğunu varsayalım aralığı için [ 0 , N ) . Daha sonra kolayca çözümlerin gerçekleştirebilmesi S n + 2 den S , n . Boyut n ile son derece hızlı büyüyeceğinden , tüm kümeleri bellekte tutmak yerine bir jeneratör yazmak iyi olabilir, aşağıdaki Python örneğine bakın.Sn[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] ] )

Tüm çiftleri arayarak listeleyebilirsiniz.

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

6

Güncelleme : önceki cevabım OP'nin sormadığı iki taraflı grafiklerle ilgileniyordu. İlgili bilgi olarak şimdilik onu bırakıyorum. ancak daha uygun olan bilgi, iki taraflı olmayan grafiklerdeki mükemmel eşleşmeler ile ilgilidir.

Bu bağlamda, Propp tarafından kaydedilen ilerlemeyi özetleyen hoş bir anket var (1999 yılına kadar). Bu makaledeki fikirlerden bazıları ve ilgili linkler faydalı olabilir. TL; DR: - zor :)

--- Eski cevabın başlangıcı

Yapmak istediğin şeyin, iki taraflı bir grafikteki olası tüm mükemmel eşleşmeleri sıraladığını unutmayın. Bunu yapmak için birçok farklı algoritma vardır ve özellikle daha yeni olanlardan biri ISAAC 2001'dendir .

Temel fikir ağ akışlarını kullanarak mükemmel bir eşleşme bulmak ve daha sonra bunu alternatif döngüleri kullanarak tekrar tekrar değiştirmek (daha fazla bilgi için ağ akışları ile ilgili algoritmalar ders kitabı bölümüne bakın).


İki parçalı grafik verilen etiketli iki kümeden oluşur [0, n) ve eğer varsa ve eğer sadece (i! = J)
Joe

nKn

2
Kalıcı cevap hesaplar. ancak OP onları
saymak

hepsi grafik yapısı nedeniyle izomorfiktir, bu nedenle uygulama izinleri hakkında düşünmek iyi bir fikir olabilir (fakat sorun, kopyaları oluşturacak olmasıdır).
Kaveh

4

Seçtiğiniz her çift, artık seçemediğiniz iki satırı ortadan kaldırır. Bu fikir özyinelemeli bir algoritma kurmak için kullanılabilir (Scala'da):

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

Bu kesinlikle daha verimli bir şekilde ifade edilebilir. Özellikle, kombinasyonlar için tüm satırları göz önünde bulundurmama fikri, çağrı tarafından kullanılmaz filter.


Bu, aynı zamanda her sayı içermeyen, ancak genişletilemeyen kombinasyonları da geri getiremez mi, çünkü orijinal dizide onları uzatabilecek çiftler yok? Eğer öyleyse, bu kombinasyonların filtrelenmesi gerekir.
Carl Mummert

OP, her sayıyı almamızı önerdi; ancak, eğer çoğaltmasız yeterince büyük bir setimiz varsa. ayarında ve tümü (sıralanmış) giriş olarak çiftler, bu doğrudur ve algoritmamın (iddia edilen şekilde) doğru olduğu ayardır. n2N-
Raphael

Scala'yı okuyamıyorum, ancak endişelendiğim konu bu. Girişin yalnızca bir çifti olduğunu varsayalım ve n = 4(0,1)n=4 . O zaman hiçbir çıktı olmamalıdır, çünkü setin tamamı kaplanamaz. Bu durumda, bu algoritma hala bir şey döndürür mü?
Carl Mummert

Evet. Ancak dediğim gibi cevabım OP'nin önerdiği senaryo ile ilgilidir, yani keyfi girdiler değil.
Raphael

Orijinal soruyu okuduğumda, keyfi bir çiftler kümesi hakkında, OP hiçbir zaman tüm çiftlerin mümkün olduğunu söylemiyor. Ancak OP'nin bu konuda daha net olabileceği konusunda hemfikirim.
Carl Mummert

4

Soruya çoktan güzel cevaplar gelse de, arkasındaki temel, genel hileyi belirtmenin iyi olacağını düşünüyorum.

Birleştirilecek öğelerin toplam siparişini verebiliyorsanız, benzersiz kombinasyonlar oluşturmak çok daha kolaydır . Bu şekilde, yalnızca sıralanmış kombinasyonlara izin verdiğimizde benzersizlik garanti edilir. Sıralanan kombinasyonları üretmek de zor değil - sadece normal kaba kuvvet numaralandırma araştırmasını yapın, ancak her adımda sadece her adımda önceden seçilmiş olanlardan daha büyük olan elemanları seçin.

Bu özel problemdeki ekstra komplikasyon, sadece uzunluk n / 2 (maksimum uzunluk) kombinasyonlarını elde etme isteğidir. İyi bir sıralama stratejisine karar verirsek, bunu yapmak zor değildir. Örneğin, Carl Mummet'in cevabında da belirtildiği gibi, eğer bir sözlükbilimsel sıralama düşünürsek, (sorudaki şemada soldan sağa), her zaman bir sonraki elementi alma stratejisini türetiriz; en küçük hala kullanılmayan sayı.

Diğer uzunluktaki dizileri oluşturmak istiyorsak bu stratejiyi genişletebiliriz. Unutmayın ki, ilk numarası mevcut en küçük sayı olmayan bir sonraki öğeyi seçtiğimizde, bir veya daha fazla öğe sırasını sıralanan sırada görünmesini engelleriz, bu nedenle prermutasyonun maksimum uzunluğu buna bağlı olarak azalır.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.