پنج شنبه, تیر 18. 1388ZOJ Monthly Contest, June 2009 Analysisبرای مشاهده ی توضیح و بررسی سوال های مسابقه ی ZOJ Monthly Contest, June 2009 به http://wiki.pykello.net/doku.php?id=zju:june09 مراجعه کنید. البته هنوز ناقص است، ولی امیدوارم کامل تر کنم :) البته از هر گونه کمکی استقبال می کنم :) پ.ن. : توضیح سوال D کامل تر شد. چهارشنبه, تیر 3. 1388Topcoder SRM 443برای مشاهده بررسی سوال ها و راه حل ها به http://wiki.pykello.net/doku.php?id=tc:srm_443 مراجعه کنید. بررسی عملکرد من در این مسابقه: - برای سوال آسان، می توانستم با کمی بیشتر فکر کردن راه حلی آسان تر پیدا کنم، و امتیاز بیشتری بدست بیاورم. این اشتباه، خیلی بزرگ نبود و در نتیجه خیلی تاثیر نداشت. - سوال متوسط: اشتباهی که کردم، این بود که ابتدا از کنارهای راه های الگوریتمی به سرعت گذشتم و سعی کردم راه های ریاضی و فرمولی پیدا کنم. بدیهی بود که می شد این سوال را با BFS حل کرد، ولی BFS عادی زمان زیادی لازم داشت و مناسب نبود. ولی اکثر مواقع ارزش دارد که آدم راه های درست با زمان بد را بیشتر بررسی کند، که در اکثر مواقع منجر به راه حلی خوب می شود. که این مورد هم یکی از آن موارد بود. بالاخره، پس از صرف مدت قابل توجهی بر روی راه های ریاضی و عدم موفقیت، بدون اینکه به اندازه ی کافی فکر کنم، چون زمان کمی باقی مانده بود، سعی کردم راه حل BFS ای با مقداری بهینه سازی ساده بنویسم شاید جواب دهد. ولی با اینکه بر روی خیلی از تست ها خوب جواب می داد، بر روی برخی تست های دستی بیشتر از زمان مجاز 2 ثانیه طول می کشید، و برای همین submit نکردم. یک اشتباه دیگر این بود که به شکل خاص این گراف دقت نکردم. به آسانی با کمی تامل می شد BFS را طوری طراحی کرد که در زمان خیلی خوبی اجرا شود. - سوال سخت: با توجه به اینکه اکثر زمان را بر روی سوال متوسط صرف کردم، به این سوال تقریبا وقتی نرسید، و بنابراین برای این سوال تقریبا هیچ کار اشتباهی انجام ندادم :) - مرحله Challenge: اصولا آدم باید طوری عمل کند که برای داشتن رتبه ی خوب و افزایش rating نیازی به امتیازهای challenge نداشته باشد، و تنها برای بیشتر شدن افزایش rating در این مرحله تلاش کند. به هر حال، چون در حل مساله ها خوب عمل نکرده بودم، به این مرحله امید داشتم که در این مرحله نیز 50 امتیاز از دست دادم و نتیجه بدتر از پیش شد. دو کد در اتاق ما بود که با توجه به ranklist احتمال زیاد اشتباه بودند (و بودند)، اشتباه اول من این بود که کد شخصی با رتبه بهتر را زودتر باز کردم (اشتباه بود، چون بقیه نیز همین کار را می کنند، و برای اینکه احتمال اینکه فرصت Challenge پیدا کنم بیشتر باشد، بهتر است کدی که توسط شخص با رتبه بدتر نوشته شده است را زودتر باز کنم، یعنی بر عکس بقیه). به هر حال، 100 امتیاز مفت را در اینجا از دست دادم، و دو challenge ناموفق هم کردم و در کل 50 امتیاز در این مرحله از دست دادم. یکی از کدهایی که با عدم موفقیت challenge کردم، به طور واضحی اشتباه بود، ولی test case من به طرز احمقانه ای آسان بود و کد طرف درست جواب داد. به هر حال، در این مرحله چند تصمیم استراتژیک بهتر دیگر می شد گرفت، ولی چون این مرحله خیلی مهم نیست، بیشتر به این مرحله نمی پردازم. به هر حال، rating ام به اندازه 109 تا کاهش پیدا کرد، ولی کاملا امیدوارم که بتوانم در مسابقات بعدی خوب عمل کنم و دوباره به rating بالاتر دست پیدا کنم :) امیدوارم تا پایان امسال بتوانم به 2650 برسم. البته برای این کار باید 5-6 مسابقه مداوم بدون اشتباه و خوب عمل کنم. سه شنبه, تیر 2. 1388ZOJ Monthly Contest, Feburary 2009بررسی سوال های مسابقه ی ZOJ Monthly Contest, Feburary 2009 : به http://wiki.pykello.net/doku.php?id=zju:feburary09 مراجعه کنید. دوشنبه, تیر 1. 1388POJ Founder Monthly Contest – 2008.07.27بررسی سوال های مسابقه ی POJ Founder Monthly Contest 2008.07.27 : به http://wiki.pykello.net/doku.php?id=pku:2008-07-27 مراجعه کنید. دوشنبه, دی 24. 1386Yungom
توضیح سوال D مسابقه ی منطقه ای تهران 2007 توسط تیزترین عضو تیم Tiz Boys: ارسلان موسویان.
به غیر از ارسلان، دو نفر دیگر هم قول همکاری داده اند، و احتمالا یک نفر دیگر هم همکاری کند. پ.ن: یک تغییر کوچولو تو متن مقاله انجام شد. دوشنبه, دی 17. 1386November Rainسلام،
چهارشنبه, مهر 18. 1386Paratroopersمساله:جدولی mxn داريم که در برخی از خانه های آن درختی قرار گرفته است. در بالای هر ستون و در سمت چپ هر سطر تفنگی قرار گرفته است که با شليک کردن آن تفنگ تمام درختان موجود در آن سطر يا ستون نابود می شوند. شليک کردن هر کدام از تفنگ ها هزينه ای دارد. می خواهيم زيرمجموعه ای از اين تفنگ ها را شليک کنيم به طوری که تمام درختان قطع شوند و حاصل ضرب هزينه ها کمينه شود. (این مساله، یکی از مسائل مسابقه ی انتخابی دانشگاه امیرکبیر در سال 1385 بود. لینک مساله در سایت acm.zju.edu.cn) ![]() توضيح و بررسی راه حل: ابتدا برای ساده تر کردن مساله، به جای کمينه کردن حاصل ضرب هزينه ها، لگاريتم حاصل ضرب هزينه ها را کمينه می کنيم. در نتيجه مساله تبديل می شود به: زيرمجموعه ای از اين تفنگ ها را انتخاب کنيد به طوری که تمام درختان را قطع کنند و حاصل جمع لگاريتم هزينه ها را کمينه شود. پس می خواهيم عبارت زير را کمينه کنيم: ![]() و در انتها جواب مساله ی اصلی برابر خواهد بود با: ![]() خوب، برای حل کردن اين مساله، گرافی به شکل زير می سازيم: ![]() که در گراف بالا r1 … r6 متناظر با سطرها می باشند و c1 … c9 متناظر با ستون ها می باشند. از s به هر کدام از سطرها يالی وصل می کنيم که وزن اين يال برابر با لگاريتم هزينه ی تفنگ آن سطر می باشد، و از هر کدام از ستون به t يالی وصل می کنيم که وزن اين يال برابر با لگاريتم هزينه ی تفنگ آن ستون می باشد. همچنين بين ri و cj يالی به وزن بی نهايت متصل می کنيم در صورتيکه در مکان [i,j] جدول درختی موجود باشد. همچنين عمل انتخاب تفنگ يک سطر را متناظر با حذف کردن يال بين s و آن سطر در نظر می گيريم و عمل انتخاب تفنگ يک ستون را متناظر با حذف کردن يال بين آن ستون و t در نظر می گيريم. حالا انتخابی از تفنگ ها را در نظر بگيريد که تمام درخت ها را قطع کند. خاصيت اين انتخاب چيست؟ خاصيت اين انتخاب اين است که به ازای هر يال ri به cj (که متناظر با يک درخت می باشد) بايد حداقل يکی از يال های s به ri (که متناظر با تفنگ سطر می باشد) و cj به t (که متناظر با تفنگ ستون می باشد) حذف شده باشد (که متناظر با انتخاب شدن آن تفنگ می باشد). نتيجه ی اين عمل چيست؟ نتيجه ی اين عمل اين است که هيچ مسيری از s به t وجود نخواهد داشت که از اين يال ri به cj عبور کند (چون فقط يک مسير اين چنين داشتيم، و حال با حذف حداقل يک يال از آن، اين تنها مسير را هم از بين می بريم.) پس اگر بخواهيم تمام درخت ها را از بين ببريم، نبايد هيچ مسيری بين s و t باشد. بنابراين مساله ی ما تبديل شد به حذف کردن تعدادی از يال های گراف مذکور به طريقی که هيچ مسيری بين s و t نباشد و مجموع وزن های اين يال های انتخاب شده کمينه باشد. اين جمله شما را به ياد چه مساله ی مشهوری می اندازد؟ احتمالا اکثر شما با مساله ی مشهور Minimum Cut آشنا هستيد. اگر آشنا نيستيد: مساله ی Minimum Cut: می خواهيم تعدادی از يال های يک گراف را حذف کنيم به طوری که هيچ مسيری بين مبدا و مقصد نباشد و مجموع هزينه های يال های حذف شده می نيمم باشد. و اگر با روش حل اين مسال آشنا نيستيد، بايد عرض کنم که جواب اين مساله (کمترين هزينه) با جواب مساله ی Maximum Flow يکی می باشد. اگر با اين مساله و طريقه ی حل آن آشنا نيستيد، به لينک 1 و لينک 2 مراجعه کنيد. بنابراين برای حل کردن مساله، پس از ساختن گراف مذکور، با يکی از الگوريتم های معروف Maximum Flow، جواب مساله را بدست می آوريم! به همين سادگی و زيبايي! سه شنبه, اردیبهشت 25. 1386Ivan and the bugsامروز به بررسی مساله Collecting Bugs که یکی از سوالات ACM/ICPC 2004 NEERC Northern Subregional و همچنین یکی از سوالات آخرین مسابقه هفتگی ما بود می پرازم. صورت سوال: n نوع شیء آبی و از هر کدام به اندازه ی بی نهایت و s نوع شیء زرد و از هر کدام به اندازه ی بی نهایت داریم. هر روز یک شیء آبی و یک شیء قرمز را به تصادف انتخاب می کنیم. هنگامی که از هر نوع شیء آبی حداقل یکی و هر نوع شیء قرمز حداقل یکی انتخاب کرده باشیم دیگر ادامه نمی دهیم. می خواهیم امید ریاضی تعداد روزهایی که به آخر کار می رسیم را پیدا کنیم. طبق تجربه، در چنین مواردی که حداکثر تعداد روزها معلوم نیست، نباید به راه حلی که به ازای هر مقداری احتمال رخداد آن را حساب کرد و جمع حاصل ضرب مقادیر در احتمالات نتیجه را حساب کرد. و باز هم طبق چندین سوال احتمالاتی که تا حالا دیده ام، این گونه مسائل اکثر با برنامه سازی پویا قابل حل شدن می باشند. برای آشنایی و یادگیری بیشتر در باره ی مسائل احتمالاتی در مسابقات برنامه نویسی و دیدن چندین مثال دیگر به مقاله ی Understanding Probabilitiesسایت Topcoder مراجعه کنید. فرض کنید Fi,j امید ریاضی حالتی باشد که در آن تعداد اشیاء آبی که تا به حال هیچ وقت انتخاب نشده اند i و تعداد اشیاء قرمز که تا به حال هیچ وقت انتخاب نشده اند برابر j باشد. چندین حال برای جفت i و j داریم: 1- i = 0 و j = 0: در این صورت دیگر لازم نیست هیچ روزی ادامه دهیم و جواب برابر با 0 خواهد بود. 2- i = 0 و j != 0: به هر حال باید یک روز انتخاب را انجام دهیم. در این روز به احتمال j/s شیء زردی که قبلا هیچ وقت انتخاب نکردیم را انتخاب می کنیم و در روز های بعد باید با j-1 شی انتخاب نشده ی زرد ادامه دهیم، و با احتمال s-j)/s) یکی از اشیاء زردی را که قبلا انتخاب کردیم را انتخاب می کنیم و در روز های بعد باید با j شی انتخاب نشده ی زرد ادامه دهیم. بنابراین Fi,j در این حالت برابر خواهد بود با: که با ساده کردن معادله ی بالا برای F0,j بدست می آوریم: 3- حالت سوم وقتی i != 0 و j = 0. با استدلالی مشابه حالت قبلی برای این حالت بدست خواهیم آورد: 4- حالتی که i != 0 و j != 0: در این صورت با احتمال i/n \* j/s شیء آبی جدید و شیء زرد جدیدی انتخاب خواهیم کرد، با احتمال n-i)/n \* j/s) شیء زرد جدید انتخاب خواهیم کرد ولی شیء آبی جدیدی انتخاب نمی کنیم، ... که در این صورت Fi,j برابر خواهد بود با: که با ساده کردن معادله ی بالا خواهیم داشت: و کد من برای حل این مساله:
At the data-structure department of Macrohard!امروز به بررسی مساله ی K-th Number که یکی از سوالات ACM/ICPC 2004 NEERC Northern Subregional و همچنین آخرین مسابقه ی هفتگی ما بوده می پردازم. صورت مساله این است که n تا عدد داریم و می خواهیم پرسش هایی از نوع: "k-امین کوچکترین عدد در بین اعداد i-ام تا j-ام چیست؟" مثلا اگر n عدد ما عبارت باشند از: {1,5,2,6,3,7,4} ، سومین کوچکترین عدد بین اعداد 2-ام تا 5-ام (یعنی {5,2,6,3} ) برابر 5 می باشد و اولین کوچکترین عدد بین اعداد 4-ام تا 4-ام برابر 6 می باشد. بدیهی ترین راه این است که برای هر پرسش اعداد i-ام تا j-ام را مرتب کنیم و k-امین کوچکترین را به عنوان خروجی چاپ کنیم. ولی در این صورت برای پاسخ به هر پرسش زمانی از مرتبه ی (O(n*log n صرف خواهیم کرد که با توجه به اینکه حداکثر 5000 پرسش از این نوع را می خواهیم پاسخ دهیم این راه حل چندان مناسب نمی باشد. کلید اصلی حل این سوال این است که می توانیم به پرسش "چند عدد کوچکتر یا مساوی عدد m در بین اعداد a-ام تا b-ام وجود دارد؟" در زمان (O(log2 n پاسخ داد. در نتیجه با استفاده از پاسخ این پرسش و جستجوی دودوئی می توان هر پرسش را در زمان (O(log3 n پاسخ داد. در زیر شبه-کد مربوط به این قسمت را مشاهده می کنید:
حال، به بررسی اینکه چگونه می توان تعداد اعداد کوچکتر یا مساوی یک عدد را بین اعداد a-ام تا b-ام به دست آورد می پردازیم. برای این کار، از درختی دودوئی استفاده می کنیم. مثلا برای مثال بالا این درخت به شکل زیر خواهد بود:
ریشه ی این درخت نماینده ی کل اعداد می باشد. فرزند سمت چپ هر گره نماینده ی نیمه ی اول بازه ی مربوط به آن گره و فرزند سمت راست نماینده ی نیمه ی دوم بازه ی مربوط به آن گره می باشد. همچنین برای هر کدام از گره ها اعداد موجود در بازه ی مربوط به آن را به صورت مرتب شده داریم. بدیهی است که می توان هر بازه را معادل با یک سری گره در این درخت در نظر گرفت که تعداد آن گره ها از مرتبه (O(log n می باشد. مثلا برای بازه ی 2 تا 7، گره های 3-2 و 7-4، برای بازه ی 3 تا 5 گره های 3-3 و 5-4 و ... با استفاده از جستجوی دودوئی می توان مشخص کرد که در یک آرایه ی مرتب چند عدد کوچکتر یا مساوی یک عدد خاص وجود دارد. پس برای مشخص کردن تعداد اعداد کوچکتر مساوی یک عدد در بازه ای خاص، گره های مربوط به آن بازه را در درخت پیدا می کنیم و با استفاده از جستجوی دودوئی در آرایه ی مربوط به هر گره تعداد اعداد کوچکتر مساوی در کل بازه را بدست می آوریم. پیچیدگی زمانی این مرحله از مرتبه ی (O(log2 n می باشد. حالا توضیح می دهیم که درخت بالا را چگونه می سازیم. برای ساختن درخت بالا از یک آرایه استفاده می کنیم که عنصر با اندیس یک ریشه ی درخت می باشد و فرزندان گره با اندیس i گره هایی با اندیس های 2i و 2i+1 می باشند. در این آرایه، برای هر گره نگه می داریم که آرایه ی مرتب شده مربوط به آن گره در کجا قرار دارد. من در راه حل خودم آرایه های مرتب شده را در یک آرایه ی دیگر ذخیره کرده ام و در آرایه ی اصلی برای هر گره اندیس شروع و طول مکانی که آرایه ی مرتب شده مربوط به آن گره در آن قرار دارد را نگهداری می کنیم. در زیر تابع مربوط به ایجاد این درخت را مشاهده می کنید:
این تابع اندیس شروع و طول قسمتی از آرایه را که می خواهیم به درخت اضافه کنیم و همچنین اندیس گرهی از درخت که این قسمت از آرایه به آن اضافه خواهد شد را می گیرد. برای درست کردن کل درخت، آن را با پارامترهای (Create(0,n,1 صدا می کنیم. و بالاخره، به بررسی روش انتخاب گره های مناسب برای بدست آوردن جواب مساله می پردازیم. فرض کنید می خواهیم گره هایی از زیردرخت با ریشه ی root را انتخاب کنیم که بازه ی مربوط به هر کدام از این گره ها کاملا زیر مجموعه ای از بازه ی مورد نظر باشند و هیچ دو گرهی وجود نداشته باشد که پدرشان یکی باشد و بازه ی مربوط به پدرشان نیز زیر مجموعه ی بازه ی مورد نظر باشد. برای این کار، چند حالت وجود دارد: 1- بازه ی مربوط به root هیچ اشتراکی با بازه ی مورد نظر ندارد. در این صورت هیچ کدام از فرزندان root عضو مجموعه گره های مورد نظر نیست. و نیازی نیست فرزندانش را بررسی کنیم. 2- بازه ی مربوط به root زیرمجموعه ی بازه ی مورد نظر می باشد. در این صورت خود گره root داخل مجموعه گره های مورد نظر می باشد. و نیازی نیست فرزندانش را بررسی کنیم. 3- بازه ی مربوط به root زیر مجموعه ی بازه ی مورد نظر نمی باشد، ولی با بازه ی مورد نظر اشتراک دارد. در این صورت خود گره root داخل مجموعه ی گره های مورد نظر نمی باشد ولی تعدادی از گره های موجود در زیر درخت آن متعلق به این مجموعه می باشد. در این صورت فرزندان root را باید بررسی کنیم. شبه کد تابع مربوط به انتخاب گره ها به شکل زیر خواهد بود:
گمان کنم توضیحات بالا برای حل مساله ی مورد نظر کافی باشد. ولی اگر همچنان مشکلی داشتید یا پیشنهادی داشتید comment بگذارید! این مساله مثال خوبی بود برای یادگیری کار کردن با درخت های دودوئی برای پاسخ دادن به query های مربوط به یک آرایه. برای تمرین بیشتر توصیه می کنم مسائل ساده تر زیر را نیز حل کنید: - Unreal Story : که البته این سوال یک راه حل خیلی ساده تر و تمیزتر هم دارد. ولی به هر حال آن را می توان با این روش نیز حل کرد. سه شنبه, فروردین 14. 1386Base -1 + iبا استفاده از 1- + i به عنوان مبنای دستگاه اعداد، که در آن i برابر با می باشد، تمام اعداد صحيح مختلط (اعدادی که دارای يک قسمت حقيقی و يک قسمت موهومی می باشند) را می توان به صورت اعداد بدون علامت متشکل از دنباله ای از يک و صفر نمايش داد. و اين [...] با استفاده از 1- + i به عنوان مبنای دستگاه اعداد، که در آن i برابر با فرض کنيد می خواهيم نمايش عدد 2 در اين مبنا را بدست بياوريم. اين کار را می توانيم با استفاده از روش معمول تبديل مبنا انجام دهيم: يعنی 2 را بر 1- + i تقسيم کنيم، سپس خارج قسمت آن را بر 1- + i تقسيم کنيم، و اين کار را تا جايي انجام دهيم که خارج قسمت بدست آمده صفر شود. سپس با پشت سر هم گذاشتن باقيمانده های تقسيم ها نتيجه ی مورد نظر را بدست آوريم. می خواهيم باقيمانده های بدست آمده صفر يا يک باشند. برای اينکه ببينيم اين کار همواره ممکن است، فرض کنيد می خواهيم يک عدد صحيح دلخواه به فرم a + bi را بر 1- + i تقسيم کنيم. می خواهيم q و r را چنان پيدا کنيم که q يک عدد مختلط و r برابر 1 يا 0 باشد و رابطه ی زير برقرار باشد: a + bi = (qr + qii)(-1 + i) + r که در آن qr نشانگر قسمت حقيقی q و qi نشانگر قسمت موهومی q می باشد. با برابر قرار دادن قسمت های موهومی و حقيقی و حل دو معادله ی دو مجهولی روابط زير برای qr و qi بدست می آيد: qr = (b - a + r) / 2 qi = (-a - b + r) / 2 واضح است که اگر a و b هر دو زوج يا هر دو فرد باشند، با قرار دادن r = 0 ، q يک عدد صحيح مختلط خواهد بود و در صورتی که يکی از a و b فرد و ديگری زوج باشد، می توانيم r را برابر با 1 انتخاب کنيم تا q يک عدد صحيح مختلط شود.
در ادامه از روش بالا برای پيدا کردن نمايش عدد 2 در اين مبنا استفاده می کنيم: مرحله ی اول: a = 2 و b = 0. در نتيجه qr = -1 و qi = -1 و r = 0. يادداشت: منبع مطالبی که خوانديد، کتاب Hacker’s Delight از انتشارات Addison Wesley می باشد. علت اينکه اين بخش از کتاب توجه مرا جلب کرد اين بود که اين مطلب مرتبط با سوال UVa #11180 می باشد که قبلا با همکاری هم تيمی های عزيز با استفاده از يک راه حل ديگر حل کرده بوديم، ولی روش ما به سادگی اين روش نبود. البته اين نشان گر اين است که اگر روابط مربوط به مساله را با دقت بررسی کنيم، معمولا به راحتی به راه حل های ساده تر و تميز تر می رسيم. دوشنبه, فروردین 13. 1386Histograms - Part 2در قسمت قبل به طرح مساله ی زير و يک ايده ی ساده برای حل آن پرداختيم: "يک سری مستطيل با عرض واحد و ارتفاع های مختلف داريم که کنار هم قرار گرفته اند. الگوريتمی پيشنهاد دهيد که مساحت بزرگترين مستطيلی که درون اين مستطيل ها جا می شود را پيدا کند." در اين قسمت روش ديگری برای حل اين مساله ارائه می کنيم: روش دوم (Iterative): ايده ی اين روش اين است که عريض ترين مستطيلی که هم ارتفاع با يکی از مستطيل ها باشد بازه ای شامل مستطيل هايي با ارتفاع های بزرگتر مساوی اين ارتفاع می باشد. مستطيل ها را به ترتيب ارتفاع بررسی می کنيم. در هر مرحله يک سری بازه داريم (که در ابتدا خالی است) و در هر مرحله بازه ی مستطيلی که بررسی می شود را به اين بازه های اضافه می کنيم. (منظورم از بازه، بازه ای از محور x ها است که هر مستطيل اشغال می کند. مثلا برای سمت چپ ترين مستطيل، اين بازه [0,1]، برای بعدی [1,2] و … می باشد.) اميدوارم توانسته باشم ايده ی اين روش را خوب توضيح بدهم. برای نگهداری بازه ها، از دو آرايه با نام های Left و Right که طول آن ها N (که N تعداد مستطيل ها می باشد) استفاده می کنيم که مقدار اوليه ی عناصر آن ها 1- می باشد. برای يک بازه عضو متناظر با سمت راست ترين عضو آن بازه در آرايه ی Right انديس سمت چپ ترين عضو آن بازه را نگه داری می کند و عضو متناظر با سمت چپ ترين عضو آن بازه در آرايه ی Left انديس سمت راست ترين عضو آن بازه را نگه داری می کند. چون هميشه ما فقط با دو سر بازه کار داريم، مقاديری که در اعضای متناظر با ساير اعضای آرايه نگه داری می شود برای ما اهميتی ندارد. در اين صورت، pseudo-code الگوريتم فوق به صورت زير خواهد بود: Heights = [3, 6, 9, 7, 11, 8, 14, 4, 6, 3, 5] Left = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] Right = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] function FindLargestRectangle(): print FindLargestRectangle() پيچيدگی زمانی اين الگوريتم از مرتبه ی ((O(n*log(n می باشد. منتظر قسمت های بعدی باشيد!
چهارشنبه, فروردین 8. 1386Histograms - Part 1به مساله ی زير توجه کنيد: "يک سری مستطيل با عرض واحد و ارتفاع های مختلف داريم که کنار هم قرار گرفته اند. الگوريتمی پيشنهاد دهديد که مساحت بزرگترين مستطيلی که درون اين مستطيل ها جا می شود را پيدا کند." (برای امتحان کردن روش های مختلف حل اين مساله، سعی کنيد مساله ی ZJU #1985 را حل کنید.) مثلا در شکل زير، مستطيلی که مساحت آن جواب مساله است با رنگ سبز مشخص شده است. ![]()
ساده ترين راه حلی که به ذهن می رسد اين است که به ازای هر مستطيل فرض کنيم که مستطيل نتيجه هم ارتفاع با آن است و ببينيم با اين ارتفاع چقدر می توانيم به سمت راست و چپ برويم. ولی پيچيدگی زمانی اين راه حال در بدترين حالت (O(n^2 می باشد که چندان مطلوب نيست. چيزی که اين مساله را برای من جالب کرده اين است که اين مساله چندين راه حل جالب و متنوع دارد و بسيار آموزنده و سرگرم کننده می باشد. در اين قسمت و قسمت های بعدی به بررسی برخی از اين الگوريتم ها که بلدم می پردازم. روش اول (Divide and Conquer): دفعه ی اولی که اين مساله را سر امتحان ميان ترم درس طراحی الگوريتم ها ديدم، اين راه حل به ذهنم رسيد: فرض کنيد می خواهيم جواب را برای مستطيل a-ام تا b-ام پيدا کنيم. اين مستطيل ها را از وسط به دو قسمت تقسيم می کنيم. جواب يا کاملا در قسمت سمت چپ است يا کاملا در قسمت سمت راست يا اينکه قسمتی از آن در سمت راست است و قسمتی از آن در سمت چپ. دو حالت اول را به صورت بازگشتی پيدا می کنيم و برای پيدا کردن بهترين جواب در حالت سوم، به روش زير عمل می کنيم: در هر مرحله مستطيل را با ارتفاع جاری گسترش می دهيم. حالا، از سمت چپ و راست به دو مستطيل مختلف مماس می شود. ارتفاع جاری را به ماکزيمم ارتفاع اين دو مستطيل تغيير می دهيم و ادامه می دهيم. در هر مرحله مساحت مستطيل جاری را پيدا کرده و جواب را بروز می کنيم. اين کارها را تا زمانی انجام می دهيم که از سمت چپ به مستطيل a-ام و از سمت راست به مستطيل b-ام برسيم. برای اينکه منظور من را دقيق تر بفهميد، به pseudo-code زير توجه کنيد: Heights = [3, 6, 9, 7, 11, 8, 14, 4, 6, 3, 5] function FindLargestRectangle(a, b): print FindLargestRectangle(0, len(Heights)-1) رابطه ی بازگشتی زمان اين الگوريتم: T(n) = 2*T(n/2) + O(n) که اگر آن را حل کنيم، بدست می آوريم که پيچيدگی زمانی اين الگوريتم از مرتبه ی ((O(n*log(n می باشد. در قسمت های بعدی راه های ديگری برای حل اين مساله را بررسی می کنم.
(Page 1 of 2, totaling 22 entries)
» next page
|
Me
Me = { "Name": "Hadi", "Job": "Programmer", "Hobbies": [ "Thinking", "Reading", "Walking", "Living" ], ... } Favorite LinksCategoriesSyndicate This BlogBlog AdministrationWeblog Statistics |
