Dikey görünürlük sorunu için etkili algoritmalar


18

Bir problem üzerinde düşünürken, aşağıdaki görevi çözen verimli bir algoritma oluşturmam gerektiğini fark ettim:

Sorun: tarafları eksenlere paralel olan iki boyutlu bir yan taraf kare kutusu verilir n. Üstünden bakabiliriz. Bununla birlikte, m yatay segmentler de vardır. Her segment bir tamsayıdır sahip y -coordinate ( 0yn ) ve x -coordinates ( 0x1<x2n ) ve bağlanır noktası (x1,y) ve (x2,y) en (önceki Resim aşağıda).

Kutunun üstündeki her birim segment için, bu segmente bakarsak kutunun içinde ne kadar derin görünebileceğimizi bilmek isteriz.

x{0,,n1}maxi: [x,x+1][x1,i,x2,i]yi

Örnek: aşağıdaki resimdeki gibi bulunan ve segmenti verildiğinde sonuç . Kutunun içine ne kadar derin ışık girebileceğine bakın.n=9m=7(5,5,5,3,8,3,7,8,7)

Yedi bölüm;  gölgeli kısım ışıkla ulaşılabilecek bölgeyi gösterir

Neyse ki bizim için hem ve olan oldukça küçük ve biz off-line hesaplamalar yapabilirsiniz.nm

Bu sorunu çözmenin en kolay algoritması kaba kuvvettir: her segment için tüm diziyi çaprazlayın ve gerektiğinde güncelleyin. Ancak, bize çok etkileyici bir vermez .O(mn)

Büyük bir gelişme, sorgu sırasında segment üzerindeki değerleri en üst düzeye çıkarabilen ve son değerleri okuyabilen bir segment ağacı kullanmaktır. Daha fazla açıklamayacağım, ancak zaman karmaşıklığının olduğunu görüyoruz .O((m+n)logn)

Ancak, daha hızlı bir algoritma buldum:

anahat:

  1. Segmentleri azalan koordinatına göre sıralayın (sayma sıralamasının bir varyasyonunu kullanarak doğrusal zaman). Şimdi, eğer herhangi bir birim segmenti daha önce herhangi bir segment tarafından kaplanmışsa, aşağıdaki hiçbir segmentin artık bu birim segmentinden geçen ışık demetini bağlayamayacağını unutmayın. Sonra kutunun üstünden altına doğru bir çizgi süpürme yapacağız.yxx

  2. Şimdi bazı tanımları tanıtalım : birim bölümü, x- koordinatları tamsayı olan ve uzunluğu 1 olan taramadaki hayali bir yatay bölümdür. Süpürme işlemi sırasında her bölüm işaretlenmemiş olabilir (yani, kutunun üst kısmı bu segmente ulaşabilir) veya işaretli (karşıt durum). Her zaman işaretlenmemiş x 1 = n , x 2 = n + 1 olan bir x birimi segmentini düşünün . Ayrıca S 0 = { 0 } , S 1 =xxxx1=nx2=n+1 . Her kümede,aşağıdakiişaretlenmemişbölümlebirlikteardışıkişaretli bir x birimi birimi (varsa) yeralacaktır.S0={0},S1={1},,Sn={n} x

  3. Bu segmentler üzerinde çalışabilen ve verimli bir şekilde ayarlanabilen bir veri yapısına ihtiyacımız var. Maksimum x- birim segment indeksini ( işaretlenmemiş segmentin endeksi) tutan bir alan tarafından genişletilen bir birleştirme birliği yapısı kullanacağız .x

  4. Şimdi segmentleri verimli bir şekilde idare edebiliriz. En şimdi düşünüyoruz diyelim -inci başlar segmentin ( "sorgusu" diyoruz), x 1 ve uçları x 2 . İ- segmentinin içinde yer alan tüm işaretlenmemiş x- birimi segmentlerini bulmamız gerekir (bunlar tam olarak ışık demetinin yolunu bitireceği segmentlerdir). Aşağıdakileri yapacağız: ilk olarak, sorgunun içindeki ilk işaretlenmemiş segmenti buluruz ( x 1'in içerdiği kümenin temsilcisini bulun ve tanımı gereği işaretlenmemiş segment olan bu kümenin maksimum dizinini alın ). Sonra bu endeksix1x2 xix1 , sorgunun içindedir, sonuca ekleyin (bu segment için sonuç y'dir ) ve bu dizini işaretleyin ( x ve x + 1 içerenbirleşimkümeleri). Ardından,işaretlenmemiştümsegmentleribulana kadar bu işlemi tekrarlayın, yani bir sonrakiSorgubulbize dizin x x 2 verir .xyxx+1xx2

Her bir birleşim işleminin yalnızca iki durumda gerçekleştirileceğini unutmayın: ya bir segmenti düşünmeye başlarız ( kez olabilir) ya da sadece bir x- birim segmenti işaretledik (bu n kez olabilir). Bu nedenle, genel karmaşıklığı O ( ( n- + m ) α ( n ) ) ( α olan bir Ackermann fonksiyonu ters ). Bir şey net değilse, bu konuda daha fazla ayrıntı verebilirim. Belki biraz zamanım varsa resim ekleyebilirim.mxnO((n+m)α(n))α

Şimdi "duvara" ulaştım. Doğrusal bir algoritma bulamıyorum, ancak bir tane olması gerektiği anlaşılıyor. İki sorum var:

  • Yatay segment görünürlük problemini çözen bir doğrusal zaman algoritması ( ) var mı?O(n+m)
  • Değilse, görünürlük sorununun olduğunun kanıtı nedir?ω(n+m)

M segmentlerinizi ne kadar hızlı sıralıyorsunuz?
babou

@babou, soru, sorunun dediği gibi doğrusal zamanda ("sayım sıralamasının bir varyasyonunu kullanarak doğrusal zaman") çalışan sayım sıralamasını belirtir.
DW

Soldan sağa doğru süpürmeyi denedin mi? Tek ihtiyacınız üzerinde tasnif edilir ve x 2 hem O ( m ) ve O ( m ) sağa yürümeye adımları tekrarlayın. Yani toplamda O ( m ) . x1x2O(m)O(m)O(m)
invalid_id

@invalid_id Evet, denedim. Bununla birlikte, bu durumda, süpürme çizgisi, segmentin başlangıcını karşıladığında (başka bir deyişle, segmentin koordinatına eşit olan sayıyı multiset'e eklediğinde ), segmentin sonunu karşıladığında ( y -koordinat) ve en yüksek aktif segmenti (çoklu sette maksimum çıkış değeri) çıktılar. Bunu (amortismanlı) sabit zamanda yapmamıza izin veren veri yapılarını duymadım. yy
mnbvmar

@ mnbvmar aptalca bir öneri olabilir, ama büyüklüğünde bir dizi hakkında , her hücreyi O ( n ) süpürür ve durdurursunuz . Evry hücre için size maksimum biliyorum y ayrıca bir değişkenle genel maksimum takip edebilir ve matris içinde girebilirsiniz. nO(n)y
invalid_id

Yanıtlar:


1
  1. İlk çeşit, hem ve x 2 iki ayrı dizilerde hatlar koordinatlarını bir ve B . O ( m )x1x2ABO(m)
  2. Ayrıca aktif segmentleri takip etmek için yardımcı bit dizisi boyutu de koruyoruz .n
  3. Soldan sağa doğru süpürmeye başlayın:
  4. için (i=0,i<n,i++)
  5. {
  6. ..if ile y değeri c , O ( 1 )x1=iyc O(1)
  7. .. {
  8. .... bul ( )max
  9. .... mağaza ( ) O ( 1 )maxO(1)
  10. ..}
  11. ..if ile y değeri c , O ( 1 )x2=iyc O(1)
  12. .. {
  13. .... bul ( )max
  14. .... mağaza ( ) O ( 1 )maxO(1)
  15. ..}
  16. }

find(max) can be implemented using an bit array with n bits. Now whenever we remove or add an element to L we can update this integer by setting a bit to true or false respectively. Now you have two options depending on the programming language used and the assumption n is relatively small i.e. smaller than longlongint which is at least 64 bits or a fixed amount of these integers:

  • Get the least significant bit in constant time is supported by some hardware and gcc.
  • By converting L to an integer O(1) you will get the maximum (not directly but you can derive it).

I know this is quite a hack because it assumes a maximum value for n and hence n can be seen as a constant then...


As I see, assuming you have got 64-bit x86 processor, you are able to handle only n64. What if n is in the order of millions?
mnbvmar

Then you'll need more integers. With two integers you can handle n up to 128, etc. So the O(m) maximum finding step is hidden in the number of integers required, which you might still optimize if m is small. You mentioned in your question that n is relatively small so I guessed it is not in the order of millions. By the way long long int is always at least 64bits by definition even on a 32-bit processor.
invalid_id

Of course it is true, C++ standard defines long long int as at least 64-bit integer type. However, won't it be that if n is huge and we denote the word size as w (usually w=64), then each find will take O(nw) time? Then we would end up with total O(mnw).
mnbvmar

Yes, unfortunately for big values of n that is the case. So now I wonder how big n will be in your case and whether it is bounded. If it is indeed in the order of millions this hack-around will not work anymore, but if cwn for low c values it will be fast and practically O(n+m). So the best algorithm choice is, as usual, input dependent. For example for n100 insertion sort is normally faster then merge sort, even with a running time of O(n2) compared to O(nlogn).
invalid_id

3
I am confused by your choice of formatting. You know you can typeset code here, right?
Raphael

0

I don't have a linear algorithm, but this one seems to be O(m log m).

Sort the segments based on the first coordinate and height. This means that (x1, l1) always comes before (x2, l2) whenever x1 < x2. Also, (x1, l1) at height y1 comes before (x1, l2) at height y2 whenever y1 > y2.

For every subset with the same first coordinate, we do the following. Let the first segment be (x1, L). For all other segments in the subset: If the segment is longer than the first, then change it from (x1,xt) to (L, xt) and add it to the L-subset in the proper order. Otherwise drop it. Finally, if the next subset has a first coordinate less than L, then split the (x1,L) to (x1, x2) and (x2, L). Add the (x2, L) to the next subset in the correct order. We can do this because the first segment in the subset is higher and covers the range from (x1, L). This new segment may be the one which covers (L, x2), but we won't know that until we look at the subset which has first coordinate L.

After we run through all of the subsets, we will have a set of segments which don't overlap. To determine what the Y value is for a given X, we only have to run through the remaining segments.

So what is the complexity here: The sort is O(m log m). Looping through the subsets is O(m). A lookup is also O(m).

So it seems that this algorithm is independent of n.

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.