ऊर्ध्वाधर दृश्यता समस्या के लिए कुशल एल्गोरिदम


18

एक समस्या पर सोचने के दौरान, मुझे एहसास हुआ कि मुझे निम्नलिखित कार्य को हल करने के लिए एक कुशल एल्गोरिथ्म बनाने की आवश्यकता है:

समस्या: हमें साइड दो-आयामी वर्ग बॉक्स दिए गए हैं जिनके किनारे कुल्हाड़ियों के समानांतर हैं। हम इसे शीर्ष के माध्यम से देख सकते हैं। हालाँकि, क्षैतिज खंड भी हैं। प्रत्येक खंड में एक पूर्णांक -coordinate ( ) और -coordinates ( ) होता है और बिंदुओं को जोड़ता है और (देखो नीचे चित्र)।nmy0ynx0x1<x2n(x1,y)(x2,y)

हम बॉक्स के शीर्ष पर प्रत्येक इकाई खंड के लिए जानना चाहते हैं, यदि हम इस खंड के माध्यम से देखते हैं तो हम बॉक्स के अंदर कितनी गहराई से देख सकते हैं।

औपचारिक रूप से, , हम ।x{0,,n1}maxi: [x,x+1][x1,i,x2,i]yi

उदाहरण: नीचे दिए गए चित्र के अनुसार n=9 और m=7 खंड दिए गए हैं, परिणाम (5,5,5,3,8,3,7,8,7) । देखो कि गहरे प्रकाश बॉक्स में कैसे जा सकते हैं।

सात खंड;  छायांकित भाग उस क्षेत्र को इंगित करता है जिसे प्रकाश द्वारा पहुँचा जा सकता है

हमारे लिए सौभाग्य से, दोनों n और m कर रहे हैं काफी छोटे और हम बंद लाइन संगणना कर सकते हैं।

इस समस्या को हल करने वाला सबसे आसान एल्गोरिथ्म ब्रूट-फोर्स है: प्रत्येक सेगमेंट के लिए पूरे एरे को ट्रैस करें और जहां आवश्यक हो उसे अपडेट करें। हालांकि, यह हमें बहुत प्रभावशाली ओ (एमएन) नहीं देता है O(mn)

एक महान सुधार एक सेगमेंट ट्री का उपयोग करना है जो क्वेरी के दौरान सेगमेंट पर मूल्यों को अधिकतम करने और अंतिम मूल्यों को पढ़ने में सक्षम है। मैं आगे इसका वर्णन नहीं करूंगा, लेकिन हम देखते हैं कि समय जटिलता ।O((m+n)logn)

हालाँकि, मैं एक तेज़ एल्गोरिथ्म के साथ आया:

रूपरेखा:

  1. कोर्डिनेट के घटते क्रम में सेगमेंट को क्रमबद्ध करें (रैखिक समय की गिनती के भिन्नता का उपयोग करके)। अब ध्यान दें कि यदि पहले किसी भी खंड द्वारा किसी भी -itit खंड को कवर किया गया है, तो कोई भी निम्न खंड इस -unit खंड से गुजरने वाले प्रकाश किरण को बाध्य नहीं कर सकता है। फिर हम बॉक्स के ऊपर से नीचे तक एक लाइन स्वीप करेंगे।x xyxx

  2. अब आइए कुछ परिभाषाओं को प्रस्तुत करते हैं: -unit खंड स्वीप पर एक काल्पनिक क्षैतिज खंड है जिसका निर्देशांक पूर्णांक हैं और जिनकी लंबाई 1. है। स्वीपिंग प्रक्रिया के दौरान प्रत्येक खंड या तो अनमार्क किया जा सकता है (यानी, एक प्रकाश किरण से जा रहा है) बॉक्स के शीर्ष इस सेगमेंट तक पहुँच सकते हैं) या चिह्नित (विपरीत मामले)। हमेशा से अचिह्नित , साथ -unit खंड पर विचार करें । आइए सेट । प्रत्येक सेट के लगातार एक पूरी अनुक्रम में शामिल होंगे चिह्नित (यदि कोई हो तो) एक निम्नलिखित के साथ क्षेत्रों -unit अचिह्नितx x x 1 = n x 2 = n + 1 S 0 = { 0 } , S 1 = { 1 }xxxx1=nx2=n+1xS0={0},S1={1},,Sn={n} x खंड।

  3. हमें एक डेटा संरचना की आवश्यकता है जो इन सेगमेंट और सेट पर कुशलतापूर्वक संचालित करने में सक्षम हो। हम अधिकतम -unit सेगमेंट इंडेक्स ( अचिह्नित सेगमेंट का इंडेक्स ) रखने वाले क्षेत्र द्वारा विस्तारित खोज-संघ संरचना का उपयोग करेंगे ।x

  4. अब हम सेगमेंट को कुशलता से संभाल सकते हैं। मान लें कि अब हम क्रम में -th सेगमेंट पर विचार कर रहे हैं (इसे "क्वेरी" कहें), जो में शुरू होता है और में समाप्त होता है । हमें सभी अचिह्नित यूनीट सेगमेंट को खोजने की आवश्यकता है जो कि -th सेगमेंट के अंदर समाहित हैं (ये बिल्कुल ऐसे सेगमेंट हैं जिन पर प्रकाश किरण अपना रास्ता समाप्त कर देगी)। हम निम्नलिखित करेंगे: सबसे पहले, हम क्वेरी के अंदर पहला अनचेक्ड सेगमेंट पाते हैं ( सेट का प्रतिनिधि खोजें जिसमें समाहित है और इस सेट का अधिकतम इंडेक्स प्राप्त करें, जो परिभाषा द्वारा अनमार्क्ड सेगमेंट है )। तब यह सूचकांकx 1 x 2 x i x 1 x yमैंएक्स1एक्स2 xix1xक्वेरी के अंदर है, इसे रिजल्ट में जोड़ें (इस सेगमेंट का परिणाम ) और इस इंडेक्स को चिन्हित करें ( और सहित यूनियन सेट )। फिर इस प्रक्रिया को तब तक दोहराएं जब तक कि हम सभी अनचाहे खंडों को न पा लें , यानी अगली खोज क्वेरी हमें सूचकांक ।yएक्स + 1 एक्स एक्स 2xx+1xx2

ध्यान दें कि प्रत्येक खोज-संघ ऑपरेशन केवल दो मामलों में किया जाएगा: या तो हम एक सेगमेंट पर विचार करना शुरू कर सकते हैं (जो कि टाइम हो सकता है ) या हमने सिर्फ एक सेनिट सेगमेंट (यह बार हो सकता है ) को चिह्नित किया है । इस प्रकार कुल मिलाकर जटिलता है ( है एकरमैन समारोह उलटा एक )। यदि कुछ स्पष्ट नहीं है, तो मैं इस पर अधिक विस्तार कर सकता हूं। अगर मेरे पास कुछ समय है तो शायद मैं कुछ तस्वीरें जोड़ पाऊंगा।mxnO((n+m)α(n))α

अब मैं "दीवार" पर पहुँच गया। मैं एक रैखिक एल्गोरिथ्म के साथ नहीं आ सकता, हालांकि ऐसा लगता है कि एक होना चाहिए। तो, मेरे दो सवाल हैं:

  • क्या क्षैतिज खंड दृश्यता समस्या को हल करने के लिए एक रेखीय-समय एल्गोरिथ्म (यानी, ) है?O(n+m)
  • यदि नहीं, तो इस बात का क्या प्रमाण है कि दृश्यता समस्या ?ω(n+m)

कितनी तेजी से आप अपने एम सेगमेंट को क्रमबद्ध करते हैं?
बबौ

@ बाबू, यह प्रश्न गिनती के प्रकार को निर्दिष्ट करता है, जैसा कि सवाल कहता है, रैखिक समय में चलता है ("गिनती के प्रकार का उपयोग करके रैखिक समय")।
डीडब्ल्यू

क्या आपने बाएं से दाएं स्वीप करने की कोशिश की? आप सभी की जरूरत पर छँटाई है और एक्स 2 में दोनों हे ( मीटर ) और हे ( मीटर ) सही करने के लिए चलने के लिए कदम दूर है। तो कुल हे ( एम ) मेंx1x2O(m)O(m)O(m)
अमान्य_आईडी

@invalid_id हां, मैंने कोशिश की। हालाँकि, इस मामले में स्वीप लाइन को तब उचित रूप से प्रतिक्रिया देनी चाहिए जब यह खंड की शुरुआत (दूसरे शब्दों में, खंड के -ordordinate के बराबर संख्या को मल्टीसेट में जोड़ें), खंड के अंत से मिलती है ( y की घटना को हटा दें) -कोर्डिनेट) और उच्चतम सक्रिय सेगमेंट (मल्टीसेट में आउटपुट अधिकतम मूल्य) को आउटपुट करता है। मैंने किसी भी डेटा संरचनाओं के बारे में नहीं सुना है जो हमें निरंतर समय में (परिशोधन) में ऐसा करने की अनुमति देता है। yy
mnbvmar

@ mnbvmar शायद एक गूंगा सुझाव है, लेकिन आकार की एक सरणी के बारे में कैसे , आप हर सेल O ( n ) को स्वीप करते हैं और रोकते हैं । ईव्री सेल के लिए आप अधिकतम y जानते हैं और आप इसे मैट्रिक्स में दर्ज कर सकते हैं, इसके अलावा आप एक चर के साथ समग्र अधिकतम का ट्रैक रख सकते हैं। nO(n)y
अमान्य_id

जवाबों:


1
  1. पहले दो अलग-अलग सरणियों और बी में लाइनों के और x 2 निर्देशांक को पहले क्रमबद्ध करें । ( एम )x1x2ABO(m)
  2. हम सक्रिय खंडों पर नज़र रखने के लिए एक सहायक बिट सरणी आकार भी बनाए रखते हैं।n
  3. बाएं से दाएं स्वीप करना शुरू करें:
  4. के लिए (i=0,i<n,i++)
  5. {
  6. ..if साथ y मूल्य हे ( 1 )x1=iyc O(1)
  7. .. {
  8. .... खोजें ( )max
  9. .... स्टोर ( ) O ( 1 )maxO(1)
  10. ..}
  11. ..if साथ y मूल्य हे ( 1 )x2=iyc O(1)
  12. .. {
  13. .... खोजें ( )max
  14. .... स्टोर ( ) O ( 1 )maxO(1)
  15. ..}
  16. }

ढूँढें ( ) n बिट्स के साथ एक बिट सरणी का उपयोग करके लागू किया जा सकता है । अब जब भी हम एल में एक तत्व को हटाते हैं या जोड़ते हैं तो हम इस पूर्णांक को क्रमशः सही या गलत के रूप में सेट करके अपडेट कर सकते हैं। अब आपके पास उपयोग की गई प्रोग्रामिंग भाषा के आधार पर दो विकल्प हैं और धारणा n अपेक्षाकृत छोटा है यानी l o n g l o o n g i n t से कम है जो कि कम से कम 64 बिट या इन पूर्णांकों की एक निश्चित राशि है:maxnLnlonglongint

  • निरंतर समय में कम से कम महत्वपूर्ण बिट प्राप्त करें कुछ हार्डवेयर और gcc द्वारा समर्थित है।
  • को पूर्णांक O ( 1 ) में परिवर्तित करने से आपको अधिकतम (सीधे नहीं बल्कि आप इसे प्राप्त कर सकते हैं) प्राप्त करेंगे।LO(1)

मुझे पता है कि यह काफी हैक है क्योंकि यह लिए अधिकतम मूल्य मानता है और इसलिए n को एक स्थिर के रूप में देखा जा सकता है ...nn


के रूप में मैं देख रहा हूँ, यह मानते हुए आप 64-बिट x86 प्रोसेसर मिल गया है, आप केवल संभाल करने में सक्षम हैं । क्या होगा यदि n लाखों के क्रम में है? n64n
mnbvmar

फिर आपको अधिक पूर्णांक की आवश्यकता होगी। दो पूर्णांकों के साथ आप को 128 तक संभाल सकते हैं , आदि इसलिए O ( m ) अधिकतम खोज चरण आवश्यक पूर्णांकों की संख्या में छिपा है, जिसे आप अभी भी ऑप्टिमाइज़ कर सकते हैं यदि m छोटा है। आपने अपने प्रश्न में उल्लेख किया है कि n अपेक्षाकृत छोटा है इसलिए मैंने अनुमान लगाया कि यह लाखों के क्रम में नहीं है। वैसे लंबे लंबे int हमेशा 32-बिट प्रोसेसर पर भी परिभाषा के अनुसार कम से कम 64 बिट है। nO(m)mn
invalid_id

बेशक, यह सच है, सी ++ मानक long long intकम से कम 64-बिट पूर्णांक प्रकार के रूप में परिभाषित करता है । हालांकि, यह नहीं होगा कि अगर विशाल है और हम के रूप में शब्द आकार निरूपित डब्ल्यू (आमतौर पर डब्ल्यू = 64 ), तो प्रत्येक ले जाएगा हे ( nnww=64findसमय? फिर हम कुलO(mn)को समाप्त कर देंगेO(nw)O(mnw)
mnbvmar

हाँ, दुर्भाग्य से बड़े मूल्यों के लिए यही मामला है। तो अब मुझे आश्चर्य है कि आपके मामले में कितना बड़ा एन होगा और क्या यह बाध्य है। यदि यह लाखों लोगों के क्रम में वास्तव में है इस हैक के आसपास अब काम नहीं करेगा, लेकिन अगर w n कम के लिए मूल्यों यह तेजी से और व्यावहारिक रूप से हो जाएगा हे ( n + मीटर ) । तो सबसे अच्छा एल्गोरिथ्म पसंद है, हमेशा की तरह, इनपुट निर्भर। उदाहरण के लिए n insert 100 सम्मिलन के प्रकार सामान्य रूप से तेज़ होते हैं, फिर मर्ज के प्रकार, यहाँ तक कि O ( n 2 ) के चालू समय की तुलना मेंnncwncO(n+m)n100O(n2)O(nlogn)
अमान्य_आईडी

3
मैं आपके स्वरूपण के चयन से भ्रमित हूं। आप जानते हैं कि आप यहाँ कोड टाइप कर सकते हैं, है ना?
राफेल

0

मेरे पास एक रैखिक एल्गोरिथ्म नहीं है, लेकिन यह एक ओ (एम लॉग एम) लगता है।

पहले समन्वय और ऊंचाई के आधार पर खंडों को क्रमबद्ध करें। इसका मतलब यह है कि X1 (x2, l2) हमेशा पहले आता है (x2, l2) जब भी X1 <x2। इसके अलावा, (X1, l1) ऊंचाई पर y1 पहले (X1, l2) ऊंचाई पर आता है जब भी y1> y2।

उसी पहली समन्वय के साथ प्रत्येक सबसेट के लिए, हम निम्नलिखित करते हैं। पहले खंड को (X1, L) होने दें। सबसेट में अन्य सभी सेगमेंट के लिए: यदि सेगमेंट पहले से अधिक लंबा है, तो इसे (X1, xt) से (L, xt) में बदलें और इसे उचित क्रम में L-subset में जोड़ें। नहीं तो गिरा दो। अंत में, यदि अगले उपसमूह में L से कम पहला समन्वय है, तो (X1, L) को (X1, x2) और (x2, L) में विभाजित करें। सही क्रम में अगले सबसेट में (x2, L) जोड़ें। हम यह कर सकते हैं क्योंकि सबसेट में पहला खंड अधिक है और (X1, L) से सीमा को कवर करता है। यह नया सेगमेंट वह हो सकता है जो कवर करता है (L, x2), लेकिन हम यह नहीं जान पाएंगे कि जब तक हम सबसेट को नहीं देखते हैं, जिसमें पहले L का समन्वय है।

जब हम सभी सबसेट के माध्यम से भाग लेंगे, तो हमारे पास एक सेगमेंट होगा जो ओवरलैप नहीं होगा। यह निर्धारित करने के लिए कि किसी दिए गए X के लिए Y मान क्या है, हमें केवल शेष खंडों के माध्यम से चलना होगा।

तो यहां क्या जटिलता है: सॉर्ट ओ (एम लॉग एम) है। सबसेट के माध्यम से लूपिंग हे (एम) है। एक लुक भी O (m) है।

तो ऐसा लगता है कि यह एल्गोरिथ्म n से स्वतंत्र है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.