<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-4267540809652741503</atom:id><lastBuildDate>Wed, 30 Jul 2025 06:32:40 +0000</lastBuildDate><title>codeperfection.blogspot.com</title><description></description><link>http://codeperfection.blogspot.com/</link><managingEditor>noreply@blogger.com (igormk)</managingEditor><generator>Blogger</generator><openSearch:totalResults>18</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-3932390109251504277</guid><pubDate>Thu, 11 Mar 2010 20:56:00 +0000</pubDate><atom:updated>2010-03-16T06:09:46.955-07:00</atom:updated><title>CodeFuEdit</title><description>Конечно го поставувам програмчево што го направив за парсирање на problem statements од &lt;a href=&quot;http://www.codefu.com.mk/&quot;&gt;www.codefu.com.mk&lt;/a&gt;. Изработено е уште пред година дена, не го објавив тогаш бидејќи има некои багови, не работи за сите типови на задачи, реков дека кога ќе можам ќе го средам ама некако не ми се навраќа кон стар код :) подобро би направил од ново CodeFu parser. Овој кој го поставувам овде е направен буквално за еден ден, не посветив многу време на тестирање и подобрување со менување на кодот и затоа однапред се извинувам доколку не функционира секогаш најдобро... Сепак врши работа, го користам на сите online codefu натпревари. Се користи едноставно, се копира целиот текст на problem statement заедно со примерите и се внесува. Програмата автоматски генерира почетен template за задачата заедно со код за тестирање. Начинот на кој се справувам со тестирањето во main медотот е &quot;позајмен&quot; од познатата алатка со иста функција но за Topcoder - kawagi.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://www.mediafire.com/?alogwzizgnm&quot;&gt;Dowload CodeFuEdit&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Доколку пронајдете некој баг, слободно пишете во коментар. Не планирам во скоро да правам update на програмчево но добро би било да се знае кога не функционира добро. Исто така ако имате некоја забелешка, слободно пишете.&lt;/div&gt;&lt;div&gt;Верувам дека нема да ви биде тешко да се снајдете со алаткава.&lt;/div&gt;&lt;div&gt;Се надевам ќе ви послужи за codefu натпреварите.&lt;/div&gt;&lt;div&gt;Со среќа :)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</description><link>http://codeperfection.blogspot.com/2010/03/codefuedit.html</link><author>noreply@blogger.com (igormk)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-1589310430673136882</guid><pubDate>Fri, 05 Feb 2010 00:14:00 +0000</pubDate><atom:updated>2010-02-05T05:43:49.360-08:00</atom:updated><title>Збир на елементи во подматрица</title><description>&lt;div style=&quot;text-align: left;&quot;&gt;Се мислев како да го именувам денешново пишување. Даден ни е следниот проблем:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Дадена ни е матрица. Секој член на матрицата има некоја вредност. Се смета дека вредностите на матрицата нема да се менуваат периодично (ова е многу важен услов чие значење ќе биде објаснето подоцна).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ќе го дефинираме поимот подматрица.&lt;/div&gt;&lt;div&gt;Ќе го објаснам графички. На сликата ни е дадена матрица А, и нејзина подматрица B.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgyjY8PAZ7Zbx3jkLOUx-_dE0i3YXAXLDxVpWVaVOlsxuQ-EeQLFxk3HqRH-Mop-xd14S-0uZ922THdVYXzsjsZp8EITyeK2huReTe2txhI7T_v3NUG95G8tthb377qRwbQjIB_YTlSfMh/s1600-h/slika1.jpg&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgyjY8PAZ7Zbx3jkLOUx-_dE0i3YXAXLDxVpWVaVOlsxuQ-EeQLFxk3HqRH-Mop-xd14S-0uZ922THdVYXzsjsZp8EITyeK2huReTe2txhI7T_v3NUG95G8tthb377qRwbQjIB_YTlSfMh/s320/slika1.jpg&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5434546416721193154&quot; style=&quot;cursor: pointer; width: 264px; height: 165px; &quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Се бара да се напише алгоритам кој на најефикасен начин би го пресметал збирот на елементите во подматрицата B.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ова е интересен проблем кој бара размислување и анализа. Би го класифицирал во архетипот динамичко програмирање иако може слободно да го вметнеме и во групата на математички проблеми (подоцна ќе објасниме зошто). Со проблемов се сретнав на втор колоквиум по предметот Алгоритми и структури на податоци.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Постепено ќе го анализирам проблемот во чекори. Следниве чекори можат да се применат и во други проблеми.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Прво треба проблемот добро да се сфати. Треба да се анализира што се бара и да се разгледаат примерите доколку ги има. Доколку уште не е јасно, треба да се проба со свои примери да се сфати и анализира проблемот. На пример во случајот со нашата задача&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;ред 1: 1 2 3&lt;/div&gt;&lt;div&gt;ред 2: 4 5 6&lt;/div&gt;&lt;div&gt;ред 3: 7 8 9&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ги нумерирам редовите и колоните почнувајќи од еден наместо од нула заради полесна имплементација. Со анализа на кодот ќе биде појасно зошто.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ние треба да напишеме функција sum(x1, y1, x2, y2) каде што (x1, y1) ни е горниот лев агол на подматрицата, а (x2, y2) ни е долниот десен агол на матрицата. Оваа функција треба да го врати збирот на елементите во овој потправоаголник (подматрица). Во нашиот пример:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;sum(1, 1, 3, 3) = 45&lt;/div&gt;&lt;div&gt;sum(1, 1, 2, 3) = 27&lt;/div&gt;&lt;div&gt;sum(1, 1, 1, 3) = 12&lt;/div&gt;&lt;div&gt;sum(2, 1, 3, 3) = 33&lt;/div&gt;&lt;div&gt;sum(2, 1, 2, 1) = 2&lt;/div&gt;&lt;div&gt;...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Никогаш не преминувајте на следната фаза доколку добро не го сфатите проблемот. Дури и кога мислите дека сте го сфатиле, напишете си неколку примерчиња, за секој случај. Не само што тоа ќе ви помогне да го сфатите проблемот подобро, туку може и да ви даде идеја за наоѓање на решение!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Следна фаза, барање на решение на проблемот.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Најпрост алгоритам е следниот. Ја читаме цела матрица и потоа &quot;со два фора&quot; ги поминуваме сите елементи што се во подматрицата и ги собираме. Многу едноставно. Но се бара најефикасен начин. Претходниов начин би бил брз да речеме за матрица со 1000x1000 елементи, релативно брз затоа што тоа би се извршило за помалку од секунда по повик на функцијата sum(x1, y1, x2, y2). Оставам на вас да размислете зошто не е ефикасно, што би можело да се подобри овде, дали можеби некои пресметки би се вршеле по повеќе пати? На кој начин би можело ова да се оптимизира?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ефикасноста се подобрува со користење на некои готови резултати.&lt;/div&gt;&lt;div&gt;Прва оптимизација би била ако имаме една акумулациона матрица за колони (аналогно е за редови). Оваа матрица би имала ист број на елементи како и оригиналната матрица. Што е логиката на оваа акумулациона матрица за колони. Елементот со индекс (i, j) означува сума на сите вредности од оригиналната матрица кои што се наоѓаат во ј-тата колона, а кои се наоѓаат во ред со индекс &lt;= i. Потоа во методот sum би имале само еден &quot;for&quot; т.е. би имале линеарна комплесност од една димензија на матрицата! Нема да навлегувам во детали како би се имплементирала функцијата sum во овој случај бидејќи не е тешко да се сфати доколку се размисли малку.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Откако ќе го сфатиме претходниот начин, се прашуваме дали можеме да одиме подалеку, т.е. дали можеме да ја оптимизираме функцијата толку многу што таа ќе работи во време O(C) каде што C е константа со мала вредност? Одговорот на ова прашање е да. Се служиме со сличен принцип како претходниот. Имаме две фази, имплементирање на акумулационата матрица и втора фаза имплементирање на методот sum.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Акумулациона матрица. Оваа матрица има исти димензии како и оригиналната матрица. Индексот (i, j) во матрицата означува дека вредноста поврзана со тој индекс е збир на сите елементи во матрицата кои се наоѓаат во ред со индекс &lt;= i и во колона со индекс &lt;= j.&lt;/div&gt;&lt;div&gt;Во примерот даден претходно, матрицата на акумулација би ги имала следниве вредности&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;ред 1: 1 3 6&lt;/div&gt;&lt;div&gt;ред 2: 5 12 21&lt;/div&gt;&lt;div&gt;ред 3: 12 27 45&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Генерирањето на оваа матрица се одвива во време на едно читање на матрицата, што значи најбрзо можно. Откако ќе ги објасниме принципите како се користи акумулационата матрица, ќе се навратиме на делот како најефикасно да се креира оваа акумулациона матрица.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Кратките и едноставни формули се добар показател дека користиме динамичко програмирање. Во зависност од тоа дали имаме bottom-to-up или up-to-bottom пристап, динамичкото програмирање можеме да го имплементираме итеративно или со рекурзија и мемоизација. Подетално за овие техники во друга прилика. Динамичкото програмирање овде е покарактеристично кај создавањето на акумулационата матрица, техниката за пресметка во методот sum би го нарекол само &quot;математичка финта&quot; :)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Значи при дадена акумулациона матрица М (да напоменеме дека во случајот x1 &lt;= x2 и y1 &lt;= y2),&lt;/div&gt;&lt;div&gt;sum(x1, y1, x2, y2) = m(x2, y2)-m(x1, y2)-m(x2, y1)+m(x2, y2)&lt;/div&gt;&lt;div&gt;Оваа формула многу добро се објаснува графички. Ако со симболи ги означиме правоаголниците тогаш добиваме дека:&lt;/div&gt;&lt;div&gt;area(E) = area(A)-area(B)-area(C)+area(D)&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOML1OEQBti7VBa11r9LLked_M0332-SAZuKbXnTZv2_aOnEDLdBduWzWYxsCIhS99lmZPxHKDGt3oaIcJa-9sbqFKhAwU2ZkofXZKwfuKU4itAhH2-RyJr5_VOAbVyxUcy5UnvnUsZ7kw/s1600-h/slika2.jpg&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOML1OEQBti7VBa11r9LLked_M0332-SAZuKbXnTZv2_aOnEDLdBduWzWYxsCIhS99lmZPxHKDGt3oaIcJa-9sbqFKhAwU2ZkofXZKwfuKU4itAhH2-RyJr5_VOAbVyxUcy5UnvnUsZ7kw/s320/slika2.jpg&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5434546669846824370&quot; style=&quot;cursor: pointer; width: 320px; height: 235px; &quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Акумулационата матрица може да се добие на сличен принцип. Тоа убаво се гледа од кодот, поточно во фукцијата generate(). Во програмата вметнав и една функција за тестирање.&lt;/div&gt;&lt;div&gt;Се надевам го сфативте начинот на кој треба да се пристапи кон решавање на оваа задача. Да бидам искрен, тогаш на колоквиум не ми текна овој начин, туку ја решавав задачата со вториот принцип со акумулациона матрица по колони. Пред неколку месеци се навратив на проблемот и ми текна на интересниот принцип што се користи кај двојните интеграли. Добар е проблемов за да се извежба принципот на оптимизирање на решенијата и динамичко програмирање иако не се користи баш тој архетип.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://www.mediafire.com/?tmmmjmzfogt&quot;&gt;Download source file&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Проблемот би бил целосно поинаков доколку вредностите во матрицата се менуваат периодично. Во тој случај нема да важи опишаниот алгоритам бидејќи нашите пресметки се засноваа на почетната пресметка, периодичното менување на вредностите во матрицата би предизвикало и менување на акумулационата матрица, а токму постојаноста на акумулационата матрица беше факт врз кој ја градевме функцијата sum(x1, y1, x2, y2). Проблемот кога можеме да имаме промени на вредности и повикувања на функцијата sum се решава на принцип многу поразличен од претходно опишаниот, тој принцип не се вбројува во архетипот динамичко програмирање. Еден од начините за решавање на овој проблем е со користење на &lt;a href=&quot;http://www.topcoder.com/tc?module=Static&amp;amp;d1=tutorials&amp;amp;d2=binaryIndexedTrees&quot;&gt;бинарни индексни стебла&lt;/a&gt;, многу ефикасни и навидум сложени, но сепак едноставни структури доколку се сфати принципот на кој тие функционираат. Овде нема да се задржувам на бинарните индексни стебла, но сигурно во некој од наредните post-ови ќе пишувам опширно.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</description><link>http://codeperfection.blogspot.com/2010/02/blog-post.html</link><author>noreply@blogger.com (igormk)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgyjY8PAZ7Zbx3jkLOUx-_dE0i3YXAXLDxVpWVaVOlsxuQ-EeQLFxk3HqRH-Mop-xd14S-0uZ922THdVYXzsjsZp8EITyeK2huReTe2txhI7T_v3NUG95G8tthb377qRwbQjIB_YTlSfMh/s72-c/slika1.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-7253620976001302499</guid><pubDate>Sun, 06 Dec 2009 02:14:00 +0000</pubDate><atom:updated>2009-12-05T18:51:25.934-08:00</atom:updated><title>Tower of Hanoi</title><description>&lt;div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://upload.wikimedia.org/wikipedia/commons/thumb/0/07/Tower_of_Hanoi.jpeg/300px-Tower_of_Hanoi.jpeg&quot;&gt;&lt;img src=&quot;http://upload.wikimedia.org/wikipedia/commons/thumb/0/07/Tower_of_Hanoi.jpeg/300px-Tower_of_Hanoi.jpeg&quot; border=&quot;0&quot; alt=&quot;&quot; style=&quot;cursor: pointer; width: 300px; height: 132px; &quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://upload.wikimedia.org/wikipedia/commons/thumb/0/07/Tower_of_Hanoi.jpeg/300px-Tower_of_Hanoi.jpeg&quot;&gt;&lt;/a&gt;&lt;br /&gt;Проблемот на Ханојски кули (&lt;a href=&quot;http://en.wikipedia.org/wiki/Tower_of_Hanoi&quot;&gt;Tower of Hanoi&lt;/a&gt;) е позната математичка игра.&lt;div&gt;Се состои од три стапчиња, и број на дискови со различна големина кои можат да се стават како прстен на било кое од стапчињата. Играта започнува со тоа што сите дискови се наоѓаат на првото стапче во растечки редослед од горе кон доле (најмалиот диск се наоѓа горе). Целта на играта е да се преместат сите дискови на друго стапче, но да не се прекршуваат правилата:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Во еден потег може да биде поместен само еден диск.&lt;/div&gt;&lt;div&gt;Секој потег се состои од земање на еден диск кој се наоѓа на врв на некое стапче и негово преместување најгоре врз другите дискови на некое друго стапче.&lt;/div&gt;&lt;div&gt;Не може еден диск да се постави врз друг помал диск.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Интересна игра со навистина едноставни правила. Најголем дел од вас ја сретнале загаткава како пример за рекурзија во основните курсеви за програмирање.&lt;/div&gt;&lt;div&gt;Но да бидам искрен, тогаш не сфатив кој е принципот на решавање, но после една година седнав малку подлабоко да ја проучам играва.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Рекурзивно многу е кратко решението, иако изгледа комплицирано на прв поглед.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;#include&amp;lt;iostream&amp;gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;void hanoi(int N, char from, char to, char other) {&lt;br /&gt; if (N == 0) return;&lt;br /&gt; // we move N-1 disks from &quot;from&quot; to &quot;other&quot;&lt;br /&gt; hanoi(N-1, from, other, to);&lt;br /&gt; // we move the biggest disk from &quot;from&quot; to &quot;to&quot;&lt;br /&gt; cout&amp;lt;&amp;lt;&quot;I moved &quot;&amp;lt;&amp;lt;N&amp;lt;&amp;lt;&quot; from &quot;&amp;lt;&amp;lt;from&amp;lt;&amp;lt;&quot; &quot;&amp;lt;&amp;lt;to&amp;lt;&amp;lt;&quot;\n&quot;;&lt;br /&gt; // we move N-1 disks from &quot;other&quot; to &quot;to&quot;&lt;br /&gt; hanoi(N-1, other, to, from);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main() {&lt;br /&gt; int i,j,k;&lt;br /&gt; hanoi(4, &#39;A&#39;, &#39;C&#39;, &#39;B&#39;);&lt;br /&gt; cin&amp;gt;&amp;gt;i;&lt;br /&gt; return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Еве го решението во C++. Како што можеме да забележиме, и без да ја сфатиме логиката гледаме дека е едноставна рекурзија која има почетен услов и рекурзивно двапати се повикува самата функција hanoi. Меѓувреме се печати нешто на екран.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Да го проучиме подлабоко проблемот.&lt;/div&gt;&lt;div&gt;Да ги дефинираме параметрите на функцијата и потоа преку опис на параметрите на функцијата да ја дефинираме почетната состојба.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;void hanoi(int N, char from, char to, char other);&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Првиот аргумент N претставува број на дискови кои сакаме да ги префлиме од дискот кој е обележан како from кон дискот обележан како to. Третиот параметар (иако може да се исфрли) го претставува третиот диск кој индиректно ќе биде искористен при поместувањето.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Значи ако функцијата hanoi ни го решава соодветниот генерален проблем на Ханојските кули, ние со повикување на оваа функција со параметри hanoi(N, &#39;A&#39;, &#39;C&#39;, &#39;B&#39;) го решаваме нашиот конкретен проблем, пренесување на N дискови од дискот обележан како &#39;A&#39; кон дискот обележан како &#39;C&#39;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Сега да ја разгледаме &quot;маѓијата&quot; внатре во функцијата.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Клучната чекор кој го правиме е делењето на еден проблем на потпроблеми од ист тип.&lt;/div&gt;&lt;div&gt;Значи треба некако соодветниот проблем префрлање на N дискови од дискот from кон дискот to да го поедноставиме.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ако сакаме да префлиме N дискови од дискот from, тогаш знаеме дека тие N дискови се наоѓаат најгоре на стапчето и се наредени по растечки редослед од горе кон доле. Притоа ако најгорниот диск го обележиме со 1, и како одиме надоле давајќи повисоки индекси, дискот обележан како N ќе биде најголем во оваа група од N дискови.&lt;/div&gt;&lt;div&gt;Кога добро ќе се сфати ова идеме на следна фаза.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Префрламе N дискови од A кон C така што прво префламе N-1 дискови од A кон B, потоа дискот кој што ќе остане најгоре на A го префрламе на C, потоа ги префрлуваме (N-1) -те дискови од B кон C.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Да повториме уште еднаш, овојпат наместо A ставаме from, наместо C ставаме to, наместо B ставаме other.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Префрламе N дискови од from кон to така што прво префламе N-1 дискови од from кон other, потоа дискот кој што ќе остане најгоре на from го префрламе на to, потоа ги префрлуваме (N-1) -те дискови од other кон to.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Имаме и почетен услов со кој прекинува рекурзијата, кога бројот на дискови кои треба да се префрлат е нула.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description><link>http://codeperfection.blogspot.com/2009/12/tower-of-hanoi.html</link><author>noreply@blogger.com (igormk)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-9219734117083270719</guid><pubDate>Mon, 12 Oct 2009 00:19:00 +0000</pubDate><atom:updated>2009-10-11T17:47:47.287-07:00</atom:updated><title>AVL стебла</title><description>&lt;a href=&quot;http://en.wikipedia.org/wiki/AVL_tree&quot;&gt;AVL стебло&lt;/a&gt; е балансирано бинарно стебло. За AVL стеблата важи, висините на двете потстебла секој јазол се разликуваат најмногу за 1 па затоа се вели дека е балансирано по висина. Пребарување, додавање на елемент и бришење се со комплексност O(log N) време, ова е просечно време и најлошо време истовремено, кадe N е број на јазли во стеблото пред операцијата. Додавање и бришење на елемент како операции може да вклучат ребалансирање на стеблото со една или повеќе ротации на стеблото.&lt;br /&gt;&lt;br /&gt;AVL е многу корисно за решавање на разни типови на проблеми кај кои се бара голема ефикасност. Следува мојата имплементација (во Java) и објаснување за секоја операција поединечно. Ви препорачувам пред да го разгледате кодот да прочитате повеќе за AVL стеблата, на крај има линкови.&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;class Node {&lt;br /&gt;Node left;&lt;br /&gt;Node right;&lt;br /&gt;Node parent;&lt;br /&gt;int value;&lt;br /&gt;int height;&lt;br /&gt;&lt;br /&gt;Node () {&lt;br /&gt; left = null;&lt;br /&gt; right = null;&lt;br /&gt; parent = null;&lt;br /&gt; height = 1;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Node (int value) {&lt;br /&gt; left = null;&lt;br /&gt; right = null;&lt;br /&gt; this.value = value;&lt;br /&gt; height = 1;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Јазелот е посебна класа која се состои од покажувачи кон левото и десното дете, покажувач кон родителот, вредноста што ја чува јазелот т.е. клучната информација според која се сортираат податоците (во овој случај е број) и висина на стеблото.&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;int getHeight(Node mom) {&lt;br /&gt;if (mom == null) return 0;&lt;br /&gt;return mom.height;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;int ballanceFactor(Node mom) {&lt;br /&gt;if (mom == null) return 0;&lt;br /&gt;int lh = getHeight(mom.left);&lt;br /&gt;int rh = getHeight(mom.right);&lt;br /&gt;return rh-lh;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;getHeight ја имплементирав посебно, иако во секој јазел постои променлива height. Ова е со цел да се избегне разгледување на специјален случај кога нема лево или (и) десно дете. Втората функција го дава факторот на балансираност на левото и десното потстебло, доколку вредноста што се враќа е позитивна, тоа значи дека десното потсетбло има поголема висина од левото.&lt;br /&gt;&lt;br /&gt;Следува објаснувањето за &quot;најкомплицираниот&quot; дел, ротацијата. На сликата се објаснети четирите случаи (кои воглавно се сведуваат на два симетрични).&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;Node rightRightCase(Node mom) {&lt;br /&gt;if (mom == null) return null;&lt;br /&gt;&lt;br /&gt;Node R = mom.right;&lt;br /&gt;Node T2 = R.left;&lt;br /&gt;&lt;br /&gt;if (mom.parent.left == mom) {&lt;br /&gt; mom.parent.left = R;&lt;br /&gt;} else {&lt;br /&gt; mom.parent.right = R;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;R.parent = mom.parent;&lt;br /&gt;&lt;br /&gt;R.left = mom;&lt;br /&gt;mom.parent = R;&lt;br /&gt;&lt;br /&gt;mom.right = T2;&lt;br /&gt;if (T2 != null) T2.parent = mom;&lt;br /&gt;&lt;br /&gt;mom.height = Math.max(getHeight(mom.left), getHeight(mom.right))+1;&lt;br /&gt;R.height = Math.max(getHeight(R.left), getHeight(R.right))+1;&lt;br /&gt;&lt;br /&gt;return R;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Оваа функција како аргумент прима некој јазел кој е корен на стебло. После ротацијата како резултат функцијата го враќа новиот корен на ова потстебло, т.е. десното дете. Напомена, за да работи оваа функција, јазелот кој се испраќа како аргумент треба да има десно дете (во спротивно нема логика да се прави ваква ротација и стеблото не може да има фактор на балансираност -1 кој пак е основен предуслов за некоја друга функција да го повика овој метод).&lt;br /&gt;&lt;br /&gt;R е десното дете, а Т2 е левото дете на јазелот mom. Она што во овој код го правиме е известување до родителот на mom дека дете веќе нема да му биде mom туку R. Потоа ги менуваме местата на mom и R, ротираме на лево. Потстеблото Т2 станува десно потстебло на Т2. Правиме ажурирање на висините на mom и R и како резултат функцијата враќа покажувач кон R, за да знае повикувачот на овој метод кој е јазелот кој си го сменил местото со mom.&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;Node rightLeftCase(Node mom) {&lt;br /&gt;leftLeftCase(mom.right);&lt;br /&gt;return rightRightCase(mom);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Овој случај е двојна ротација. Прво го ротираме на десно стеблото чиј корен е mom.right, па потоа  вршиме ротација на лево со референтен јазел во mom.&lt;br /&gt;&lt;br /&gt;Напомена: rightRightCase е аналогно со ротација на лево, а leftLeftCase е аналогно со ротација на десно.&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;Node leftLeftCase(Node mom) {&lt;br /&gt;if (mom == null) return null;&lt;br /&gt;Node L = mom.left;&lt;br /&gt;Node T2 = L.right;&lt;br /&gt;&lt;br /&gt;if (mom.parent.left == mom) {&lt;br /&gt; mom.parent.left = L;&lt;br /&gt;} else {&lt;br /&gt; mom.parent.right = L;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;L.parent = mom.parent;&lt;br /&gt;&lt;br /&gt;L.right = mom;&lt;br /&gt;mom.parent = L;&lt;br /&gt;&lt;br /&gt;mom.left = T2;&lt;br /&gt;if (T2 != null) T2.parent = mom;&lt;br /&gt;&lt;br /&gt;mom.height = Math.max(getHeight(mom.left), getHeight(mom.right))+1;&lt;br /&gt;L.height = Math.max(getHeight(L.left), getHeight(L.right))+1;&lt;br /&gt;&lt;br /&gt;return L;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;Node leftRightCase(Node mom) {&lt;br /&gt;rightRightCase(mom.left);&lt;br /&gt;return leftLeftCase(mom);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Овие два случаи се симетрични со rightRightCase(Node mom) и rightLeftCase(Node mom) и затоа нема повторно да ги објаснувам.&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;void ballanceTreeInsertion(Node root, Node mom) {&lt;br /&gt;int a, p;&lt;br /&gt;&lt;br /&gt;while (mom != root) {&lt;br /&gt; p = ballanceFactor(mom);&lt;br /&gt; if (p == 2) {&lt;br /&gt;  // right subtree outweighs the left subtree&lt;br /&gt;  // If the balance factor of R is +1, a left rotation is needed with P as the root.&lt;br /&gt;  // If the balance factor of R is -1, a double left rotation is needed&lt;br /&gt; &lt;br /&gt;  a = ballanceFactor(mom.right);&lt;br /&gt; &lt;br /&gt;  if (a == 1) {&lt;br /&gt;   mom = rightRightCase(mom);&lt;br /&gt;  } else {&lt;br /&gt;   if (a == -1) {&lt;br /&gt;    mom = rightLeftCase(mom);&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt; } else {&lt;br /&gt;  if (p == -2) {&lt;br /&gt;   a = ballanceFactor(mom.left);&lt;br /&gt;  &lt;br /&gt;   if (a == -1) {&lt;br /&gt;    mom = leftLeftCase(mom);&lt;br /&gt;   } else {&lt;br /&gt;    if (a == 1) {&lt;br /&gt;     mom = leftRightCase(mom);&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; mom = mom.parent;&lt;br /&gt;&lt;br /&gt; // we update the height of mom&lt;br /&gt; mom.height = Math.max(getHeight(mom.left), getHeight(mom.right))+1;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Во мојата имплементација, секое балансирано стебло има единствен корен root. Вистинскиот корен е во левото дете на root. Ова е со цел за да може да се претстави стебло со 0 елементи (root.left ќе биде null во тој случај). Исто така, ваква динамична структура често се менува внатрешно и root.left во различни моменти од времето може да има различни јазли, што е тешко да се претстави доколку не постои некој &quot;поврховен&quot; јазел како коренот со кој единствено се претставува и еднозначно се карактеризира секое стебло.&lt;br /&gt;&lt;br /&gt;Оваа функција е клучна за добивање на балансираност на стеблото при додавање на нов елемент. Како аргумент се праќа корен на дрвото и јазелот од кој почнуваме да го балансираме дрвото. Го балансираме јазелот mom и потоа се качуваме нагоре по стеблото се додека не стигнеме до коренот. Алгоритмот за балансирање е следен: во p го сместуваме факторот на балансираност на јазелот кој го обработуваме. ДОколку овој број е 2 или -2, тоа значи дека стеблото во тој јазел е небалансирано (понатаму накратко ќе го употребувам поимот балансираност во јазел, наместо балансираност на стеблото чиј корен е конкретниот јазел). Во зависност од тоа дали десното (левото) дете има фактор на балансираност 1 или -1 се одвива единечна или двојна ротација. Пред да се качиме нагоре по хиерархијата ја ажурираме висината на јазелот кој моментално го обработуваме.&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;void ballanceTreeDeletion(Node root, Node mom) {&lt;br /&gt;int a, p;&lt;br /&gt;&lt;br /&gt;while (mom != root) {&lt;br /&gt; mom.height = Math.max(getHeight(mom.left), getHeight(mom.right))+1;&lt;br /&gt;&lt;br /&gt; p = ballanceFactor(mom);&lt;br /&gt; if (p == 2) {&lt;br /&gt;  // right subtree outweighs the left subtree&lt;br /&gt;  // If the balance factor of R is +1, a left rotation is needed with P as the root.&lt;br /&gt;  // If the balance factor of R is -1, a double left rotation is needed&lt;br /&gt; &lt;br /&gt;  a = ballanceFactor(mom.right);&lt;br /&gt; &lt;br /&gt;  if ((a == 1)||(a == 0)) {&lt;br /&gt;   mom = rightRightCase(mom);&lt;br /&gt;  } else {&lt;br /&gt;   if (a == -1) {&lt;br /&gt;    mom = rightLeftCase(mom);&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt; } else {&lt;br /&gt;  if (p == -2) {&lt;br /&gt;   a = ballanceFactor(mom.left);&lt;br /&gt;  &lt;br /&gt;   if ((a == -1)||(a == 0)) {&lt;br /&gt;    mom = leftLeftCase(mom);&lt;br /&gt;   } else {&lt;br /&gt;    if (a == 1) {&lt;br /&gt;     mom = leftRightCase(mom);&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; mom = mom.parent;&lt;br /&gt;&lt;br /&gt; // we update the height of mom&lt;br /&gt; mom.height = Math.max(getHeight(mom.left), getHeight(mom.right))+1;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Оваа функција е скоро идентична на претходната, со таа разлика што овде се применува ротација на лево доколку p = 2 и (а = 1 или а = 0), и ротација на десно доколку p = 2 и (а = -1 или а = 0). Првата функција ќе ја употребуваме за балансирање при додавање на елемент, втората при бришење на елемент. Доколку ве интересира зошто е ваква имплементацијата можете да прочитате повеќе во разни книги кои се занимаваат со тематика од областа на алгоритмите и структурите на податоци.&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;void addNode(Node root, int value) {&lt;br /&gt;Node mom = root.left;&lt;br /&gt;Node newnode = new Node(value);&lt;br /&gt;Node prev = root;&lt;br /&gt;&lt;br /&gt;while (mom != null) {&lt;br /&gt; if (value &amp;lt;= mom.value) {&lt;br /&gt;  prev = mom;&lt;br /&gt;  mom = mom.left;&lt;br /&gt; } else {&lt;br /&gt;  prev = mom;&lt;br /&gt;  mom = mom.right;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;newnode.parent = prev;&lt;br /&gt;&lt;br /&gt;if (value &amp;lt;= prev.value) {&lt;br /&gt; prev.left = newnode;&lt;br /&gt;} else {&lt;br /&gt; prev.right = newnode;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// now we need to balance the tree&lt;br /&gt;mom = newnode;&lt;br /&gt;&lt;br /&gt;ballanceTreeInsertion(root, mom);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;addNode прима како аргумент корен и вредност која што сакаме да се смести во стеблото. Се изминува стеблото надоле додека не се дојде до некој &quot;null елемент&quot; и на негово место се сместува новиот. Овде важи правилото, сите лементи во левото потстебло на даден јазел се помали или еднакви на вредноста на тој јазел, а сите елементи во десното потстебло на јазелот се поголеми од неговата вредност. Откако ќе го внесеме јазелот, го балансираме новиот јазел т.е. ја повикуваме функцијата ballanceTreeInsertion која врши верижно балансирање на стеблото нагоре се до коренот.&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;void deleteNode(Node root, int value) {&lt;br /&gt;Node mom = root.left;&lt;br /&gt;Node prev = root;&lt;br /&gt;Node T;&lt;br /&gt;boolean found = false;&lt;br /&gt;&lt;br /&gt;while (mom != null) {&lt;br /&gt; if (mom.value == value) {&lt;br /&gt;  found = true;&lt;br /&gt;  break;&lt;br /&gt; }&lt;br /&gt; if (value &amp;lt;= mom.value) {&lt;br /&gt;  prev = mom;&lt;br /&gt;  mom = mom.left;&lt;br /&gt; } else {&lt;br /&gt;  prev = mom;&lt;br /&gt;  mom = mom.right;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;if (found == false) {&lt;br /&gt; //System.out.println(&quot;The element was not found&quot;);&lt;br /&gt; return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Node orig = mom;&lt;br /&gt;&lt;br /&gt;if ((orig.left == null)&amp;amp;&amp;amp;(orig.right == null)) {&lt;br /&gt; // we remove the node&lt;br /&gt; mom = orig.parent;&lt;br /&gt; if (mom.left == orig) {&lt;br /&gt;  mom.left = null;&lt;br /&gt; } else {&lt;br /&gt;  mom.right = null;&lt;br /&gt; }&lt;br /&gt; orig = null;&lt;br /&gt;&lt;br /&gt; // we should be sure that the subtree with mom with it&#39;s main root element&lt;br /&gt; // has correct heights and as parametar we give valid element&lt;br /&gt; mom.height = 1;&lt;br /&gt; ballanceTreeDeletion(root, mom);&lt;br /&gt; return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;if ((orig.left == null)^(orig.right == null) == true) {&lt;br /&gt; // if there is exactly one subtree&lt;br /&gt; mom = orig.parent;&lt;br /&gt; if (orig.left != null) {&lt;br /&gt;  T = orig.left;&lt;br /&gt;  if (mom.left == orig) {&lt;br /&gt;   mom.left = orig.left;&lt;br /&gt;   orig.left.parent = mom;&lt;br /&gt;  } else {&lt;br /&gt;   mom.right = orig.left;&lt;br /&gt;   orig.left.parent = mom;&lt;br /&gt;  }&lt;br /&gt; } else {&lt;br /&gt;  T = orig.right;&lt;br /&gt;  if (mom.left == orig) {&lt;br /&gt;   mom.left = orig.right;&lt;br /&gt;   orig.right.parent = mom;&lt;br /&gt;  } else {&lt;br /&gt;   mom.right = orig.right;&lt;br /&gt;   orig.right.parent = mom;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; orig = null;&lt;br /&gt; ballanceTreeDeletion(root, T);&lt;br /&gt; return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// the node has 2 subtrees, we need to find the smallest element of the right subtree of mom&lt;br /&gt;mom = orig.right;&lt;br /&gt;&lt;br /&gt;if (mom.left == null) {&lt;br /&gt; // special case, it is more complicated to change the relations&lt;br /&gt; if (orig.parent.left == orig) {&lt;br /&gt;  orig.parent.left = mom;&lt;br /&gt; } else {&lt;br /&gt;  orig.parent.right = mom;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; orig.left.parent = mom;&lt;br /&gt; mom.left = orig.left;&lt;br /&gt; mom.parent = orig.parent;&lt;br /&gt; orig = null;&lt;br /&gt; ballanceTreeDeletion(root, mom);&lt;br /&gt; return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;prev = mom;&lt;br /&gt;&lt;br /&gt;while (mom != null) {&lt;br /&gt; prev = mom;&lt;br /&gt; mom = mom.left;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;mom = prev;&lt;br /&gt;prev = mom.parent;&lt;br /&gt;&lt;br /&gt;// we are changing the relations instead of just changing the value&lt;br /&gt;&lt;br /&gt;if (mom.right != null) {&lt;br /&gt; mom.right.parent = mom.parent;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;T = mom.parent;&lt;br /&gt;mom.parent.left = mom.right;&lt;br /&gt;&lt;br /&gt;mom.parent = orig.parent;&lt;br /&gt;mom.left = orig.left;&lt;br /&gt;mom.right = orig.right;&lt;br /&gt;&lt;br /&gt;if (orig.parent.left == orig) {&lt;br /&gt; orig.parent.left = mom;&lt;br /&gt;} else {&lt;br /&gt; orig.parent.right = mom;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;orig.left.parent = mom;&lt;br /&gt;orig.right.parent = mom;&lt;br /&gt;&lt;br /&gt;// now we need to balance the tree&lt;br /&gt;T.height = Math.max(getHeight(T.left), getHeight(T.right))+1;&lt;br /&gt;ballanceTreeDeletion(root, T);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Бришењето на јазел од стеблото е малку покомплицирано. Оваа функција како аргумент прима референца кон коренот и клучната вредност на јазелот што сакаме да биде избришан. Прво го пронаоѓаме јазелот во стеблото. Потоа разгледуваме неколку специјални случаи.&lt;br /&gt;&lt;br /&gt;Доколку јазелот е лист, т.е. нема лево и десно потстебло, тогаш јазелот едноставно го бришеме, така што ги отстрануваме врските на неговиот родител кон него, и потоа ги балансираме сите јазли додека не стигнеме нагоре до коренот на стеблото.&lt;br /&gt;&lt;br /&gt;Доколку јазелот Т има само едно потстебло, тогаш јазелот Т го отстрануваме, а притоа дете на неговиот родител ќе стане детето на Т.&lt;br /&gt;&lt;br /&gt;Доколку јазелот Т има две потстебла, тогаш го бараме најмалиот елемент од неговото десно потстебло т.е. го бараме јазелот L (ја употребувам оваа ознака за да објаснам поубаво, во кодот е имплеменирано со променливи со друго име) кој се наоѓа &quot;најлево&quot; во неговото десно потстебло. Ја отстрануваме врската од неговиот родител кон L и овој јазел го ставаме на местото на Т. Т го отстрануваме. Разбирливо, потоа вршиме балансирање на стеблото од јазелот кој претходно беше родител на L. Овде разгледав специјален случај кога L e дете на T. Малку е покомплицирано да се менуваат врските доколку јазлите се директно поврзани. На крај се одвива балансираност која започнува од претходниот родител на L.&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;void inorder(Node mom) {&lt;br /&gt;if (mom == null) return;&lt;br /&gt;&lt;br /&gt;inorder(mom.left);&lt;br /&gt;System.out.println(mom.value);&lt;br /&gt;inorder(mom.right);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;void inorderRoot(Node root) {&lt;br /&gt;inorder(root.left);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Со повикувањето на inorderRoot(Node root) се врши inorder изминување на стеблото, а тоа значи дека ќе бидат отпечатени вредностите што ги содржи стеблото и тие ќе бидат сортирани во неопаѓачки редослед.&lt;br /&gt;&lt;br /&gt;Се надевам дека сега некои работи ќе бидат појасни за AVL стеблата и ќе пробате самите да искодирате AVL стебло. За некои од можните примени на овие интересни и многу ефикасни структури во некоја следна прилика.&lt;br /&gt;&lt;br /&gt;Овој код може и да содржи некои bug-ови, па се надевам дека доколку забележете некоја ќе ме информирате, а и јас ќе сменам нешто доколку мислам дека е грешно. На тестирањата кои ги вршев стеблото си ја вршеше добро својата функција.&lt;br /&gt;&lt;br /&gt;Доколку сакате повеќе да прочитате за AVL стеблата ви препорачувам:&lt;br /&gt;&lt;br /&gt;Introduction to Algorightms&lt;br /&gt;Algorithms in C&lt;br /&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/AVL_tree&quot;&gt;http://en.wikipedia.org/wiki/AVL_tree&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;и уште многу ресурси кои можете да ги најдете пребарувајќи на google&lt;br /&gt;&lt;a href=&quot;http://www.google.com/search?hl=en&amp;amp;source=hp&amp;amp;q=avl+tree&amp;amp;aq=f&amp;amp;oq=&amp;amp;aqi=g7g-s1g2&quot;&gt;http://www.google.com/search?hl=en&amp;amp;source=hp&amp;amp;q=avl+tree&amp;amp;aq=f&amp;amp;oq=&amp;amp;aqi=g7g-s1g2&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Кодот заедно со некои тестови кои ги правев можете да го симнете овде:&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.mediafire.com/?2vnjyn2nguj&quot;&gt;http://www.mediafire.com/?2vnjyn2nguj&lt;/a&gt;</description><link>http://codeperfection.blogspot.com/2009/10/avl.html</link><author>noreply@blogger.com (igormk)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-4276688870712454792</guid><pubDate>Sun, 11 Oct 2009 21:57:00 +0000</pubDate><atom:updated>2009-12-06T16:47:15.105-08:00</atom:updated><title>Збор два за O(logN) и стеблата</title><description>Структурите секогаш одат заедно со алгоритмите. Ефикасна имплементација е збир од ефикасни податочни структури и ефикасен алгоритам. Некогаш треба и да се прави компромис. Кај многу решенија големата комплексност може да се намали со користење на добри податочни структури. На пример, кај сортирањето, комплексноста од O(N*N) значи дека за N = 1000000 програмата нема во разумно време да даде решение.&lt;br /&gt;&lt;br /&gt;Проблемот на сортирање е добро проучен и познати се алгоритми кои даваат решение во време O(N*logN). Овде ќе ги спомнам merge sort и мојот омилен heap sort. Другите сортирања имаат комлексност од O(N*N) во најлош случај. Но, другите сортирања освен оригиналната низа не користат друга меморија и некои релативно комплицирани структури (со исклучок на некои променливи како бројачи и променливи во кои привремено се чуваат податоци).&lt;br /&gt;&lt;br /&gt;Кај merge sort и heap sort приказната е поинаква. Merge sort користи две низи, значи оригиналната низа и уште една низа со иста мемориска големина (едно од следните мои пишувања ќе го посветам целосно на сортирања). Heap sort пак користи само една низа, но таа низа е организирана на друг начин кој овозможува сите операции како вметнување на елемент во структурата, бришење, наоѓање на максимум или минимум да се извршуваат во O(1) или O(logN), овие неколку операции индиректно придонесуваат во она што се бара, сортирање на низата.&lt;br /&gt;&lt;br /&gt;Стеблото е структура или поим кој се поврзува со посакуваната комплексност O(logN). Значи директно или индиректно, доколку некој проблем бара решение кое е од ред O(logN), тогаш ние ќе треба да се занимаваме со стебло, иако понекогаш стеблото не е очигледно на прв поглед, овде мислам општо, на стебло како структура и стебло како поим, како логичка организација која во својата суштина го има гранењетo.</description><link>http://codeperfection.blogspot.com/2009/10/ologn.html</link><author>noreply@blogger.com (igormk)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-869946878507054150</guid><pubDate>Thu, 10 Sep 2009 22:00:00 +0000</pubDate><atom:updated>2009-09-10T15:28:52.360-07:00</atom:updated><title>Очекувана вредност</title><description>Последниот SRM 448 ме натера да размислувам за една од моите омилени теми - Веројатност. Првата задача беше поврзана со оваа тема. Како прва и најлесна &lt;a href=&quot;http://www.topcoder.com/stat?c=problem_statement&amp;amp;pm=10615&amp;amp;rd=13902&quot;&gt;задача&lt;/a&gt;, решението се добиваше рекурзивно, со собирање на веројатностите за сите можни настани. Брзо го напишав ова затоа што инстинктот ми велеше дека ова мора да биде главниот начин за добивање на конечниот резултат. Требаше да се погоди очекуваниот број на карти кои ќе се извлечат, а кои ќе донесат победа. Нема да објаснувам што се бара во задачата, неа можете да ја погледнете на &lt;a href=&quot;http://www.topcoder.com/stat?c=problem_statement&amp;amp;pm=10615&amp;amp;rd=13902&quot;&gt;topcoder&lt;/a&gt;. Она што не знаев е како сите информации за веројатноста да се искористат за да се добие конечниот резултат. Брзо го искодирав кодот за пресметување на веројатноста. Прво размислував малку како да го искористам она што веќе го имав, но не ми доаѓаше идеја. Потоа на 40 минути до крај малку погуглав и за среќа најдов една страна каде што многу едноставно беше објаснето како се добива очекувана вредност. Формулата е следна:&lt;br /&gt;&lt;br /&gt;очекувана вредност = Сума од на сите настани(веројатноста за настан i * вредноста за тој настан i)&lt;br /&gt;&lt;br /&gt;Еве да објаснам за еден едноставен пример. Имаме коцка, таа има 6 страни и на секоја страна има по една вредност од 1 до 6. При фрлање на коцката која е очекуваната вредност што ќе ја добиеме?&lt;br /&gt;&lt;br /&gt;Значи според формулата:&lt;br /&gt;&lt;br /&gt;expected = (1/6)*1+(1/6)*2+(1/6)*3+(1/6)*4+(1/6)*5+(1/6)*6 = (1/6)*21 = 3.5&lt;br /&gt;&lt;br /&gt;Можеби и малку е нелогичен примеров ама добро покажува како се применува формулата за пресметување на очекувана вредност.&lt;br /&gt;&lt;br /&gt;Повеќе за ова можете да прочитате на &lt;a href=&quot;http://en.wikipedia.org/wiki/Expected_value&quot;&gt;wikipedia&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Инаку да се вратам на приказната со настапот на SRM 448. Го имплементирав ова, и програмата не ми ги даваше потребните резултати. Значи имаше две потенцијални работи кои се причина за грешното решение. Прво, алгоритмот не е точен, и второ, имам некоја грешка во кодот. Втората опција брзо ја елиминирав мислејќи дека во толку прост код и не може да има некоја грешка, скенирајќи го набрзина кодот за да имам време да размислувам за точноста на алгоритмот. Бидејќи малку бев скептичен во врска со точноста на формулата се обидував да наоѓам други малку поинакви пристапи во крајниот алгоритам и менував некои работи во кодот кои не ми донесоа успех. На крај се откажав. Моја среќа што имаше многу натпреварувачи со ниедна решена па не ми падна многу рејтингот, сега е 1224 и останувам во DIV 1.&lt;br /&gt;&lt;br /&gt;Кога заврши натпреварот одлучив да одморам малку. Размислував што би можело да ми биде грешката и полека го анализирав мојот код во главата. Наеднаш дојдов до проблематичниот дел. Наместо&lt;span&gt; for (j=0;j&lt;c[i];j++)&gt;&lt;c[i];j++)&gt;0) што е грешка при брзање... Оваа грешка ме чинеше добар пласман. Алгоритмот бил добар, но сум имал грешка во имплемнтацијата.&lt;br /&gt;&lt;br /&gt;Поука за друг пат. Секогаш разгледувај ги сите потенцијални причинители на грешната програма, и никогаш не елиминирај ниедна од можните причини колку и да изгледа дека непотребно се губи време на некоја од нив.&lt;br /&gt;&lt;br /&gt;&lt;/c[i];j++)&gt;&lt;/span&gt;</description><link>http://codeperfection.blogspot.com/2009/09/blog-post_10.html</link><author>noreply@blogger.com (igormk)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-1866940623802795332</guid><pubDate>Wed, 02 Sep 2009 21:49:00 +0000</pubDate><atom:updated>2009-09-02T15:00:43.732-07:00</atom:updated><title>Тест задача</title><description>Случајно најдов на еден многу интересен сајт &lt;a href=&quot;http://www.scarky.com/&quot;&gt;http://www.scarky.com/&lt;/a&gt;  каде може да се постави задача по програмирање. Сите параметри се местат од страна на креаторот, кодот за натпреварот сам се генерира. Можеби тоа што не би го сметал за професионален начин за организирање на натпревари е што нема можност повеќе input-и. Се надевам тоа ќе се поправи во иднина. Ајде сега да го тестираме системот. Производ на два броеви :) Напишете кодче и праќајте. Ќе се обидам наредниве денови да ставам некој попредизвикувачки проблем од областа на програмирањето.&lt;br /&gt;&lt;br /&gt;&lt;!-- scarky widget http://scarky.com/ --&gt;&lt;br /&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://scarky.com/widget/get/P5163817/&quot;&gt;&lt;/script&gt;&lt;br /&gt;&lt;!-- end scarky widget --&gt;</description><link>http://codeperfection.blogspot.com/2009/09/blog-post.html</link><author>noreply@blogger.com (igormk)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-6842005373206904189</guid><pubDate>Sat, 01 Aug 2009 23:48:00 +0000</pubDate><atom:updated>2009-08-01T17:23:28.261-07:00</atom:updated><title>USACO</title><description>USACO (&lt;a href=&quot;http://ace.delos.com/usacogate&quot;&gt;http://ace.delos.com/usacogate&lt;/a&gt;) е тренинг сајт за програмирање каде секој може да се регистрира и да решава. Според мене, секој кој има елементарни познавања од програмирање и се интересира за решавање на проблеми мора задолжително да го посети сајтот. Вкупно има околу 100 задачи кои се групирани во 6 chapters. Секој chapter се состои од sections. Во секоја секција има околу 3-4 задачи. Убавата и интересната работа е тоа што задачите мора да се решаваат по ред. Не може да се решава задача од некоја повисока секција додека не се решат сите претходни задачи. Во почетокот задачите се лесни, а како се напредува задачите се се потешки. Покрај задачите има и посебни лекции наречени TEXTS. Во секој TEXT е обработена некоја одредена тема од областа на програмирањето и алгоритмите. Сите основни принципи на програмирање и најбитни и најосновни алгоритми се обработени во овој тренинг. Овој тренинг пред се е наменет за средношколци кои се спремаат за натпреварите по информатика, овде пред се мислам на IOI (International Olympiad in Informatics).&lt;br /&gt;&lt;br /&gt;На овој тренинг сајт почнав да решавам кон крајот на четврта година средно (пред 2 години) кога се спремав за IOI 2007. Поради обврски кон факултетот пред се, решавав на сајтот со повремени прекини, па така дури денес можам да кажам дека ги решив сите задачи :) Сите задачи се предизвикувачки, но сепак најинтересни ми беа последните три од chapter 6. При решавање се вежба логиката и размислувањето. Некои задачи некогаш и би рекол дека се невозможни на почетокот но кога навистина добро ќе се размисли - за се има решение, само треба да се најде. Начин на решавање на задачите, прво добро да се прочита и да се сфати што е проблемот. Потоа анализа, разгледување на примери, размислување како да се тргне кон решавање. Разгледување на разни начини. Треба да се одбере најлогичниот начин кој претходно треба да е добро анализиран, прво умствено да се изврши па потоа тоа да се преточи во програмски код. Доколку некоја од овие фази се обидете да ја прескокнете или да ја поминете набрзина без добро размислување тоа најчесто се одразува на време и на нерви :) Кога ќе напишете неколку стотина линии код, гледате дека се грешка, па потоа пак од почеток - секако никој не го сака ова. Во кој програмски јазик ќе се програмира мислам дека е најмал проблем иако ова не е баш работа која може да се занемари. Предноста е кај оние кои знаат повеќе програмски јазици бидејќи ги знаат предностите и недостатоците на секој па во дадена ситуација ќе знаат да го искористат најдобриот избор. Во почетокот, кога почнав да навлегувам во водите на програмирањето кодирав во Pascal, тогаш за мене Pascal беше програмски јазик со кој можев буквално се да искодирам :) толку бев уверен и во себе и во моќта на Pascal. Потоа научив C, овој програмски јазик би го споредил во брзината и перформансите со брза спортска кола, но недостатокот е во тешкото управување со воланот :) За попрости проблеми лесно е да се пишува код во C, но кога ќе наидете на посложени проблеми кои бараат користење на посложени структури и кои имаат потреба од готови библиотеки доаѓа потреба од друг програмски јазик кој ќе ги надмине недостатоците на C, а сепак ќе ја задржи брзината. Погодувате, тоа е C++. Немам баш многу искуство во C++ bидејќи брзо мигрирав од C во Java, но тоа е јазикот кој ми беше алтернатива при решавањето доколку наидев на проблем кој го надминува временскиот лимит во Java. Иста програма напишана во Java и C++ не дава иста брзина на извршување. C++ e далеку побрз. Но сепак Java ми е омилен програмски јазик за програмирање пред се заради неговата едноставност и моќ. Во Java може да се напише буквално се и тоа процесот на кодирање е многу побрз затоа што нуди подршка од многу корисни библиотеки и добри &lt;a href=&quot;http://en.wikipedia.org/wiki/Integrated_development_environment&quot;&gt;IDE&lt;/a&gt; како &lt;a href=&quot;http://www.eclipse.org/&quot;&gt;Eclipse&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJTELKC5cnLlHSGE_44o0YFu72gmJLr9rpllYioCqw050zKpUCeTk0K7w-de4WO2-5A17bTwXsylaR34EWZOgBpJO7MJep_OvHth6WOQmeW6rlRHhUA-C9KFzeDdCzB7RybMUkJXzV_Biu/s1600-h/usaco.jpg&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 532px; height: 208px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJTELKC5cnLlHSGE_44o0YFu72gmJLr9rpllYioCqw050zKpUCeTk0K7w-de4WO2-5A17bTwXsylaR34EWZOgBpJO7MJep_OvHth6WOQmeW6rlRHhUA-C9KFzeDdCzB7RybMUkJXzV_Biu/s320/usaco.jpg&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5365154749302848098&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;It&#39;s time for a new challenge :)</description><link>http://codeperfection.blogspot.com/2009/08/usaco.html</link><author>noreply@blogger.com (igormk)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJTELKC5cnLlHSGE_44o0YFu72gmJLr9rpllYioCqw050zKpUCeTk0K7w-de4WO2-5A17bTwXsylaR34EWZOgBpJO7MJep_OvHth6WOQmeW6rlRHhUA-C9KFzeDdCzB7RybMUkJXzV_Biu/s72-c/usaco.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-3752088206080619564</guid><pubDate>Sat, 17 Jan 2009 20:21:00 +0000</pubDate><atom:updated>2010-03-16T06:03:16.843-07:00</atom:updated><title>Алгоритми. Вовед.</title><description>Многу луѓе кои се занимаваат со информатичка технологија малку знаат за тоа што се алгоритми. Напишав еден мал вовед во тоа што се алгоритми. Сите оние што се ентузијасти во полето на информатичката технологија е неопходно да имаат барем општи познавања од алгоритмите. Тоа е еден посебен свет на размислување, техники за решавање на проблеми, употреба на логика за да се стигне до резултат. Многу од помладите се скриени таленти за решавање на алгоритамски проблеми, но за жал, малку нашето образование посветува на тој дел од информатиката кој сепак е најбитен.&lt;br /&gt;&lt;br /&gt;Ги земам за пример земјите од соседството. Хрватаска е одличен пример за тоа како треба да се едуцираат млади кадри и пример за тоа како државата се грижи за своите таленти, Бугарија редовно е меѓу првите 10 земји во свет, Романија отсекогаш ги имала едни од најдобрите програмери (зборувам во светски рамки). Наскоро планирам да напишам и за тоа кои земји колку имаат постигнато во полето на програмирањето. Во ова што го напишав и што го поставив овде се вклучени и мои размислувања. Некои од податоците се земени од Интернет (wikipedia).&lt;br /&gt;&lt;br /&gt;Дури и доколку не разберете нешто ви советувам да го прочитате до крај, којзнае, можеби ќе откриете со што сакате да се занимавате во иднина... За се што ве интересира слободно контактирајте ме, оставајте коментари и прашувајте. Се надевам дека вие сте новиот талент во програмирање.&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://www.mediafire.com/?dwmn2ndrkme&quot;&gt;Algoritmi.&lt;wbr&gt;pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;</description><link>http://codeperfection.blogspot.com/2009/01/blog-post.html</link><author>noreply@blogger.com (igormk)</author><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-3758788734460225326</guid><pubDate>Wed, 03 Dec 2008 15:46:00 +0000</pubDate><atom:updated>2009-10-08T04:22:23.573-07:00</atom:updated><title>Транспортни мрежи (Network Flow)</title><description>&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhp46jGQcd2LLh_s-Dkgv2rPLnBApRaI2JcU6ui3jB8GwhgvtylSAPVAUjNDD2RJTW9b0-cHUHOCHxjdbPOKpeCrQf3J9Ge2Stwy4-Ojrk5iNbqs9GWw1Cm-kCp-ALDSPcUdZR77Yj55TKM/s1600-h/maxflow_push1.gif&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 199px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhp46jGQcd2LLh_s-Dkgv2rPLnBApRaI2JcU6ui3jB8GwhgvtylSAPVAUjNDD2RJTW9b0-cHUHOCHxjdbPOKpeCrQf3J9Ge2Stwy4-Ojrk5iNbqs9GWw1Cm-kCp-ALDSPcUdZR77Yj55TKM/s320/maxflow_push1.gif&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5278656061639838898&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Транспортна мрежа е ориентиран граф, без циклуси во кој на секое ребро (i, j) му е придружен реален број а&lt;span style=&quot;font-size:78%;&quot;&gt;ij&lt;/span&gt;&gt;=0 што се нарекува пропусна способност на реброто, и за кој важи&lt;br /&gt;&lt;ul&gt;&lt;li&gt;постои едно и само едно теме s, за кое важи дека нема ребра што влегуваат во тоа теме, кое се нарекува влезно теме или влез на мрежата&lt;/li&gt;&lt;li&gt;постои едно и само едно теме t за кое важи дека нема ребра кои што излегуваат од тоа теме, кое се нарекува излезно теме или излез од мрежата&lt;/li&gt;&lt;/ul&gt;Протокот низ секое ребро не е поголем од неговата пропусна способност.&lt;br /&gt;За секое теме освен влезното и излезното важи дека вкупниот проток што влегува во темето е еднаков со вкупниот проток што излегува од темето&lt;br /&gt;&lt;br /&gt;Алгоритмот за наоѓање максимален проток од влезот (s) до излезот (t) е следен:&lt;br /&gt;&lt;br /&gt;Алгоритмот ја започнува работата со произволен проток, што може да биде и нулти поток (се ставаат сите моментални проводности на нула). Потоа, протокот постојано се зголемува со систематска проверка на сите аугментални патеки од s кон t. Барањето на овие аугментални патеки се прави со помош на доделување ознаки на темињата кои кажуваат во правец на кои ребра и за колку потокот може да биде зголемен. Така, потокот се зголемува за максимално можна вредност и потоа повторно се ажурираат ознаките на темињата. Постапката се повторува се додека има аугментални патеки од s кон t.&lt;br /&gt;&lt;br /&gt;Овој алгоритам е познат како алгоритам на Форд-Фалкерсон и доколку потокот секогаш го зголемуваме по најкусата аугментална патека, максималниот поток се добива за помалку од |V|*|E|/2 итерации каде што со V го означуваме бројот на темиња, а со E бројот на ребра во графот.&lt;br /&gt;&lt;br /&gt;Имплементацијата во Java е следна:&lt;br /&gt;&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt; static int M;        // M is the number of vertices&lt;br /&gt; static long c[][] = new long[50][50];&lt;br /&gt; static long f[][] = new long[50][50];  // the flow&lt;br /&gt; &lt;br /&gt; static boolean busy[] = new boolean[50];&lt;br /&gt; static long ver[] = new long[50];&lt;br /&gt; static int who[] = new int[50];&lt;br /&gt; &lt;br /&gt; static void updateNeighbours(int mom) {&lt;br /&gt;  int i;&lt;br /&gt;  long newver;&lt;br /&gt;  &lt;br /&gt;  for (i=1;i&amp;lt;=M;i++) {&lt;br /&gt;   if (busy[i] == false) {&lt;br /&gt;    newver = Math.min(ver[mom], c[mom][i]-f[mom][i]);&lt;br /&gt;    &lt;br /&gt;    if (newver &amp;gt; ver[i]) {&lt;br /&gt;     ver[i] = newver;&lt;br /&gt;     who[i] = mom;&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; static boolean findPath() {&lt;br /&gt;  // we set all the vertices as unvisited&lt;br /&gt;  int i;&lt;br /&gt;  int bestv;&lt;br /&gt;  long bestscore;&lt;br /&gt;  long dec;&lt;br /&gt;  &lt;br /&gt;  for (i=1;i&amp;lt;=M;i++) {&lt;br /&gt;   busy[i] = false;&lt;br /&gt;   ver[i] = 0;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  busy[1] = true;&lt;br /&gt;  ver[1] = Integer.MAX_VALUE;&lt;br /&gt;  who[1] = 0;&lt;br /&gt;  updateNeighbours(1);&lt;br /&gt;  &lt;br /&gt;  while (busy[M] == false) {&lt;br /&gt;   // we find the best vertex found so far&lt;br /&gt;   bestv = 0;&lt;br /&gt;   bestscore = 0;&lt;br /&gt;   &lt;br /&gt;   for (i=1;i&amp;lt;=M;i++) {&lt;br /&gt;    if (busy[i] == false) {&lt;br /&gt;     if (ver[i] &amp;gt; bestscore) {&lt;br /&gt;      bestscore = ver[i];&lt;br /&gt;      bestv = i;&lt;br /&gt;     }&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   if (bestv == 0) {&lt;br /&gt;    // this means that a path has not been found&lt;br /&gt;    return false;&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   busy[bestv] = true;&lt;br /&gt;   updateNeighbours(bestv);&lt;br /&gt;   &lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  dec = ver[M];&lt;br /&gt;  i = M;&lt;br /&gt;  while (i!=1) {&lt;br /&gt;   // we work with the segment from i to who[i]&lt;br /&gt;   f[who[i]][i]+=dec;&lt;br /&gt;   f[i][who[i]]=-f[who[i]][i];&lt;br /&gt;   i=who[i];&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  return true;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; static void networkFlow() {&lt;br /&gt;  while (findPath() == true) {&lt;br /&gt;   &lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;M е бројот на темиња.&lt;br /&gt;c[i][j] е пропусната способност на реброто од i до j.&lt;br /&gt;f[i][j] е моменталната проводност по патот од i до j.&lt;br /&gt;&lt;br /&gt;Пред да се повика функцијата networkFlow() треба да се иницијализираат пропусните способности на сите ребра. Доколку нема пат од едно теме i до друго теме j тогаш c[i][j]=0. Доколку графот е насочен, т.е. може да се оди само од i до j тогаш само c[i][j] &gt; 0, а c[j][i] = 0. Доколку може да се оди во двете насоки тогаш c[i][j] == c[j][i] &gt; 0. Треба да се напомене дека при повикувањето на networkFlow(), сите елементи f[i][j] треба да бидат иницијализирани на нула.&lt;br /&gt;busy[], ver[] и who[] се низи кои се потребни за работа на алгоритмот на Дијкстра (правилниот изговор е Диџкстра, но јас го викам Дијкстра :) со кој го наоѓаме патот од изворот до излезното теме.&lt;br /&gt;&lt;br /&gt;Овој алгоритам може да се примени и за други проблеми, како што е bipartite matching problem. Проблемот може да се дефинира вака.&lt;br /&gt;Дадени ни се група на машки и група на женски и дадено ни е кој со кој си одговара :)&lt;br /&gt;Да се одреди максималниот број на парови што можат да бидат направени така што да си одговараат машкото и женското од секој пар :)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9EsZdiNgu0EvZMxVODzQ-I5F2ADBQiBN2KDhf_LH9ItAQXBAP-QrWFRlwaf7phG6FwBOGOkDu5nPCjjPa4qqp4KnqYKDE0ltVjOWziwyBWgVkTOElc5-JknUMIVpBVGA_qfrCw7dyWio0/s1600-h/hall_fig2_cropped.jpg&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 218px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9EsZdiNgu0EvZMxVODzQ-I5F2ADBQiBN2KDhf_LH9ItAQXBAP-QrWFRlwaf7phG6FwBOGOkDu5nPCjjPa4qqp4KnqYKDE0ltVjOWziwyBWgVkTOElc5-JknUMIVpBVGA_qfrCw7dyWio0/s320/hall_fig2_cropped.jpg&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5278656642099218002&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Како може да го решиме проблемот со помош на тоа што веќе го знаеме за транспортните мрежи? Земаме две темиња кои ќе бидат влезно и излезно теме. Сите темиња од групата машки ги поврзуваме со изворот, а сите темиња од групата женски ги поврзуваме со излезното теме. Ги поврзуваме само оние машки и женски кои си одговараат. Сите врски се со тежина 1, т.е. доколку темињата i и j се поврзани, тогаш c[i][j] = 1.&lt;br /&gt;&lt;br /&gt;Објаснувањето зошто треба вака да се реши проблемот го оставам на вас :)&lt;br /&gt;&lt;br /&gt;Алгоритмот за решавање на овој проблем на транспортни мрежи многу често се применува во задачи. Многу убаво објаснување за овој алгоритам и за многу други, заедно со задачи со нивна примена може да се најдат на сајтот на &lt;a href=&quot;http://ace.delos.com/usacogate&quot;&gt;USACO&lt;/a&gt;. Во скоро време ќе напишам и повеќе околу овој сајт и тоа што тој го нуди за едукација.&lt;br /&gt;&lt;br /&gt;Користена литература:&lt;br /&gt;&lt;a href=&quot;http://ace.delos.com/usacogate&quot;&gt;USACO&lt;/a&gt;&lt;br /&gt;Introduction to Algorithms - Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein&lt;br /&gt;Algorithms in C - Robert Sedgewick</description><link>http://codeperfection.blogspot.com/2008/12/network-flow.html</link><author>noreply@blogger.com (igormk)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhp46jGQcd2LLh_s-Dkgv2rPLnBApRaI2JcU6ui3jB8GwhgvtylSAPVAUjNDD2RJTW9b0-cHUHOCHxjdbPOKpeCrQf3J9Ge2Stwy4-Ojrk5iNbqs9GWw1Cm-kCp-ALDSPcUdZR77Yj55TKM/s72-c/maxflow_push1.gif" height="72" width="72"/><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-6827293396796430256</guid><pubDate>Mon, 01 Dec 2008 20:54:00 +0000</pubDate><atom:updated>2008-12-01T13:14:00.071-08:00</atom:updated><title>CodeFu, 2008 Seasonal competition!</title><description>Во недела 7 декември, во 12 часот ќе се одржи Codefu натпреварот во програмирање. Сигурно повеќето од вас имаат слушнато за овој натпревар кој иако има традиција само две години издигна стандарди за тоа како треба да се организираат натпревари кај нас, а уште поважно, на индиректен начин создаде нови програмери, како што имам кажано, за мене програмер е човек кој што знае да решава проблеми и да размислува &quot;алгоритамски&quot;, без навреда кон сите останати. Исто така на тие малкуте квалитетни програмери им го издигна нивото. На овој натпревар задачите се решаваат во Java. Задaчите се алгоритамски и логички и поделени се на тежини.&lt;br /&gt;&lt;br /&gt;Мој совет до сите што знаат да програмираат во Java (не треба којзнае колку да си специјалист во Java) но и до тие што не знаат Java , а знаат Pascal, C или C++, да се пријават. Ништо не можат да изгубат туку само да добијат. Java се учи брзо. Од лично искуство кажувам дека да се совлада само тој дел од Java кој ќе ви овозможи да решавате задачи не е многу тешко. Лани специјално за Codefu натпреварот почнав да учам Java и буквално во една вечер ги научив основите на Java. Следниот ден веќе решавав задачи од Codefu. Уште една добра работа. Кога ќе се регистрирате имате пристап до задачите од претходните години. Има околу 50 задачи од различна тежина кои можете да ги решавате и да проверите дали ви се точни или не. Слободно можете да го тестирате системот.&lt;br /&gt;&lt;br /&gt;Натпреварот ќе трае 2 часа и ќе се одвива преку Интернет. 5 задачи за 2 часа... малку звучи застрашувачки :) Наградите се примамливи iPod за победникот и уште еден за некој по случаен озбор од оние што имат над нула поени ;) Еве уште една мотивација да учествувате. Што помасовен натпревар значи поголем квалитет на кој ќе се издигнеме сите ние. Секоја чест на организаторите кои ги овозможуваат овие натпревари.&lt;br /&gt;&lt;br /&gt;Учествувајте, нема да зажалите!</description><link>http://codeperfection.blogspot.com/2008/12/codefu-2008-seasonal-competition.html</link><author>noreply@blogger.com (igormk)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-1716346995293861596</guid><pubDate>Wed, 19 Nov 2008 23:10:00 +0000</pubDate><atom:updated>2008-11-19T15:32:00.656-08:00</atom:updated><title>Прости броеви</title><description>Пак математика :) Овде ставам два алгоритми за генерирање на прости броеви.&lt;br /&gt;&lt;br /&gt;Првиот алгоритам генерира табела од која брзо може да се види дали некој број е прост.&lt;br /&gt;&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;int i,j;&lt;br /&gt;int N = 100;&lt;br /&gt;&lt;br /&gt;boolean isprime[] = new boolean[N+1];&lt;br /&gt;&lt;br /&gt;for (i=2;i&amp;lt;=N;i++) {&lt;br /&gt;  isprime[i]=true;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;for (i=2;i&amp;lt;=N;i++) {&lt;br /&gt;  if (isprime[i]==true) {&lt;br /&gt;      for (j=2*i;j&amp;lt;=N;j+=i) {&lt;br /&gt;          isprime[j]=false;&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Вториот алгоритам генерира низа во која се чуваат простите проеви.&lt;br /&gt;&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;int i,j;&lt;br /&gt;int prime[] = new int[1000];&lt;br /&gt;int numofprimes=1;&lt;br /&gt;boolean pom;&lt;br /&gt;prime[0]=2;&lt;br /&gt;&lt;br /&gt;for (i=3;i&amp;lt;1000;i++) {&lt;br /&gt;   // we check if i is a prime number&lt;br /&gt;   pom=true;&lt;br /&gt;   for (j=0;j&amp;lt;numofprimes;j++) {&lt;br /&gt;       if (prime[j]&amp;lt;=Math.sqrt((double)i)) {&lt;br /&gt;           if (i%prime[j]==0) {&lt;br /&gt;               pom=false;&lt;br /&gt;               break;&lt;br /&gt;           }&lt;br /&gt;       } else {&lt;br /&gt;           break;&lt;br /&gt;       }   &lt;br /&gt;   }&lt;br /&gt;   if (pom==true) {&lt;br /&gt;       prime[numofprimes]=i;&lt;br /&gt;       numofprimes++;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;</description><link>http://codeperfection.blogspot.com/2008/11/blog-post_8813.html</link><author>noreply@blogger.com (igormk)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-8615317939484004116</guid><pubDate>Wed, 19 Nov 2008 15:21:00 +0000</pubDate><atom:updated>2008-11-19T15:35:29.736-08:00</atom:updated><title>Пресметување на комбинации</title><description>&lt;blockquote&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;In combinatorial mathematics&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;, a &lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: rgb(0, 0, 0);&quot;&gt;combination&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt; is an un-ordered collection of distinct elements, usually of a prescribed size and taken from a given set.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpYa8s4GKrEo939LDJmJdk2qgvZDpkS940xRBzgWKS-vcxt_QIHR1IKmoKKBaJVOIADFta9UbnLE6dqG4r-D5Jde5DhjinsyfITnODHIHENhdqT1ilyfu6yu-sJrRBPIJ5LeJYbUz0oiRv/s1600-h/kombinacii.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 214px; height: 51px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpYa8s4GKrEo939LDJmJdk2qgvZDpkS940xRBzgWKS-vcxt_QIHR1IKmoKKBaJVOIADFta9UbnLE6dqG4r-D5Jde5DhjinsyfITnODHIHENhdqT1ilyfu6yu-sJrRBPIJ5LeJYbUz0oiRv/s320/kombinacii.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5270390251776603186&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;Овде ќе зборувам за алгоритам за пресметување на комбинации. Според основната дефиниција може да се направи една функција, но како што може да се забележи е многу неефикасна во смисла на тоа што n! тешко може да се смести во променлива, поради големината. На пример 15! = 1,307,674,368,000. Ова не го собира во long, а да не зборуваме за int. Ова не е единствениот недостаток на овој алгоритам, има премногу пресметки па дури и да го поправиме овој алгоритам. Има уште една работа освен комплексноста за која нема да зборувам овде. Еднаш при решавање на задача, го решив најголемиот дел на задачата, и кога дојде она &quot;најлесното&quot;, пресметување на комбинациите го оптимизирав овој алгоритам и цело време ми паѓаше на време, се додека не ми текна на нешто што го знаев од часовите по математика. Потоа направив брз алгоритам, но ми беше криво што порано не сум се сетил на тоа :) Но од грешките се учи, па тоа ми беше една добра лекција, доколку некој алгоритам е точен, но паѓа на време, размисли дали проблемот може да се реши со друг алгоритам.&lt;br /&gt;&lt;br /&gt;Решението на нашиот проблем лежи во Паскаловиот триаголник. Колку просто :)&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0nw86-qXy1FR9Z20UvPfeuAdYTjbT3OThbvmzHisvefAxiWoOs1EJ3EA3qShhyphenhyphenjmDuJEmmQeXQ65rxgi3INoZYFSfPFuped59L5S8b9MRqOKSyTLpee8eQjn4NopG-Q4Z9TZBGtB7_n5C/s1600-h/pascal.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 218px; height: 111px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0nw86-qXy1FR9Z20UvPfeuAdYTjbT3OThbvmzHisvefAxiWoOs1EJ3EA3qShhyphenhyphenjmDuJEmmQeXQ65rxgi3INoZYFSfPFuped59L5S8b9MRqOKSyTLpee8eQjn4NopG-Q4Z9TZBGtB7_n5C/s320/pascal.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5270516280762312466&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Нема да објаснувам многу за ова, повеќе можете да прочитате на &lt;a href=&quot;http://en.wikipedia.org/wiki/Pascal%27s_triangle&quot;&gt;wikipedia&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Еве една инплементација на пресметување на комбинации со помош на Паскалов триаголник.&lt;br /&gt;&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;Java&quot;&gt;&lt;br /&gt;&lt;br /&gt;long N=20;&lt;br /&gt;int i,j;&lt;br /&gt;long comb[][] = new long[N][N];&lt;br /&gt;&lt;br /&gt;for (j=0;j&amp;lt;N;j++) {&lt;br /&gt;  comb[0][j]=1;&lt;br /&gt;  comb[j][j]=1;&lt;br /&gt;  for (i=1;i&amp;lt;j;i++) {&lt;br /&gt;       comb[i][j]=comb[i-1][j-1]+comb[i][j-1];&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Како што се гледа, комплексноста на алгоритмот е O(N), а кога ни се пресметани &quot;претходните&quot; комбинации, пресметувањето на една комбинација е во константно време O(1). За да пресметаме N &quot;последователни&quot; комбинации ни треба O(N). Нема да навлегувам во понатамошни анализи :)</description><link>http://codeperfection.blogspot.com/2008/11/blog-post_19.html</link><author>noreply@blogger.com (igormk)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpYa8s4GKrEo939LDJmJdk2qgvZDpkS940xRBzgWKS-vcxt_QIHR1IKmoKKBaJVOIADFta9UbnLE6dqG4r-D5Jde5DhjinsyfITnODHIHENhdqT1ilyfu6yu-sJrRBPIJ5LeJYbUz0oiRv/s72-c/kombinacii.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-6211259880880506210</guid><pubDate>Mon, 17 Nov 2008 20:44:00 +0000</pubDate><atom:updated>2008-11-17T13:52:23.346-08:00</atom:updated><title>Теорија на веројатност</title><description>Една од математичките дисциплини кои често се предмет на проучување од страна на програмерите е Теоријата на веројатност. Една од примените е кај проблемите од типот, колкави ми се шансите да фатам на лото :)&lt;br /&gt;&lt;br /&gt;Во математиката, веројатноста да се случи еден настан А се претставува како реален број во опсегот  од 0 до 1 и се запишува како P(A). Невозможен настан има веројатност 0, и сигурен настан име веројатност 1.&lt;br /&gt;&lt;br /&gt;Спротивно или комплемент на настанот A е настанот [not A] (ова е, настанот A не се случил). Неговата веројатност се означува со P(not A) = 1 - P(A)&gt; На пример, шансата да не ти се падне шестка при фрлање на коцка е 1 - (шансата да ти се падне шест) = 1 - (1/6) = (5/6).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA8jap9SwldZI3ZeuCQys_Qe31VAaFwaS3YPRZYCmWi6Ka1thwF85VtENE53hbG67S8PzgHgixUs5jtWHVywWBK0_X48lFi-G2UP-10kLNkuv4n0bwzMwbf4-RHxH8ZTurBTPWQpFlK5tn/s1600-h/presek.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 81px; height: 21px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA8jap9SwldZI3ZeuCQys_Qe31VAaFwaS3YPRZYCmWi6Ka1thwF85VtENE53hbG67S8PzgHgixUs5jtWHVywWBK0_X48lFi-G2UP-10kLNkuv4n0bwzMwbf4-RHxH8ZTurBTPWQpFlK5tn/s320/presek.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5269735236042816594&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;Ако двата настани А и B се случат во исто време додека се врши експериментот, ова се нарекува &quot;joint probability&quot; на A и B.&lt;br /&gt;Ако двата настани А и В се независни, тогаш &quot;joint probability&quot; е:&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;text-align: left;&quot;&gt;P(A and B) = P(A) * P(B)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;пример: ако две монети се фрлени, шансата да се погоди &quot;глава&quot; и кај двете е (1/2) * (1/2) = (1/4).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSS_MzMg57Bmtua-i2izXUHaz3PjFwdQttkztYJLv9uFryeDXbVCvDvfOTc38zXsgdHARQRBLHoxoKYmbbkE4T-Rv7duDU_8mCQUv57iy3B8FFY8jGELd9m_OHVOpoqytrMeM0M9fvXVSg/s1600-h/unija.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 81px; height: 21px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSS_MzMg57Bmtua-i2izXUHaz3PjFwdQttkztYJLv9uFryeDXbVCvDvfOTc38zXsgdHARQRBLHoxoKYmbbkE4T-Rv7duDU_8mCQUv57iy3B8FFY8jGELd9m_OHVOpoqytrMeM0M9fvXVSg/s320/unija.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5269735236792069906&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;Ако се случи настанот А или настанот В, или пак се случат и двата настани истовремено, ова се нарекува унија на настаните А и В.&lt;br /&gt;Ако настаните А и В не можат да се случат истовремено т.е. тие се зависни, тогаш веројатноста да се случи еден од нив е:&lt;br /&gt;&lt;br /&gt;P(A or B) = P(A) + P(B)&lt;br /&gt;&lt;br /&gt;пример: шансата да ти се погоди 1 или 2 при фрлање на коцка е P(1 or 2) = P(1) + P(2) = (1/6 + (1/6) = (1/3)&lt;br /&gt;&lt;br /&gt;Ако настаните А и В не се зависни еден од друг тогаш:&lt;br /&gt;&lt;br /&gt;P(A or B) = P(A) + P(B) - P(A and B).&lt;br /&gt;&lt;br /&gt;На пример, при извлекувањето на една карта по случајност од еден шпил од карти, шансата да добијам &quot;срце&quot; или карта во боја (J, Q, K) (или една што е и во срце и е карта во боја) е (13/52) + (12/52) - (3/52) = (22/26), затоа што од 52 карти, 13 се во &quot;срце&quot;, 12 се карти во боја, и 3 се и двете: овде веројатноста вклучена во &quot;3 што се и двете&quot; се вклучени во секоја од &quot;13 срца&quot; и &quot;12 карти во боја&quot;, но треба да бидат избројани само еднаш.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdafshnFaBgfyQTlgFgekXif5wZIqnpqCMFeSd6gP9frteNGmo_ksY7XvMNsfAamHdaImb03TKgBjjaURLDJxzegfd6DRx4iZzz2yDCS1YNo_6GEVvIrlF4BO5TDTRmDFSh5bvYhPf9Z2j/s1600-h/uslovna.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 75px; height: 20px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdafshnFaBgfyQTlgFgekXif5wZIqnpqCMFeSd6gP9frteNGmo_ksY7XvMNsfAamHdaImb03TKgBjjaURLDJxzegfd6DRx4iZzz2yDCS1YNo_6GEVvIrlF4BO5TDTRmDFSh5bvYhPf9Z2j/s320/uslovna.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5269735412826140402&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;Условна веројатност е веројатноста да се случи некој настан А, при дадена веројатноста на друг настан B. Симболот погоре се чита &quot;веројатност на А, при дадено В&quot;. Се дефинира како:&lt;br /&gt;&lt;br /&gt;P(A | B) = P(A and B) / P(B)&lt;br /&gt;&lt;br /&gt;На пример. Земаме два настани А и В. Две фрлања на коцки А и В.&lt;br /&gt;&lt;br /&gt;A: Првата коцка паѓа на 3.&lt;br /&gt;В: Вкупната сума на погодени броеви по фрлањето на втората коцка е 8.&lt;br /&gt;&lt;br /&gt;Да претпоставиме дека ги фрламе двете коцки истовремено и ја покриваме втората коцка, па само ја гледаме коцката 1; и забележуваме дека коцката 1 паднала на 3. При дадена половична информација, веројатноста дека збирот на двете коцки ќе даде 8 не е 5/36 (2+6; 3+5, 4+4, 5+4, 6+3 од сите можни збирови на двете коцки кои се 6*6 на број) туку е 1/6, затоа што втората коцка мора да падне точно на 5 за да се постигне бараниот резултат.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.mathgoodies.com/lessons/vol6/conditional.html&quot;&gt;Повеќе информации и примери за условна веројатност.&lt;/a&gt;</description><link>http://codeperfection.blogspot.com/2008/11/blog-post_17.html</link><author>noreply@blogger.com (igormk)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA8jap9SwldZI3ZeuCQys_Qe31VAaFwaS3YPRZYCmWi6Ka1thwF85VtENE53hbG67S8PzgHgixUs5jtWHVywWBK0_X48lFi-G2UP-10kLNkuv4n0bwzMwbf4-RHxH8ZTurBTPWQpFlK5tn/s72-c/presek.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-124134739691688331</guid><pubDate>Sat, 15 Nov 2008 16:53:00 +0000</pubDate><atom:updated>2008-11-20T03:01:41.814-08:00</atom:updated><title>Најмал заеднички содржател</title><description>Евклидов алгоритам за најголем заеднички делител и најмал заеднички содржател. Може да послужи некогаш за натпревари по програмирање, па го постирам овде за да имам брз пристап до него и да го користам copy paste.&lt;br /&gt;&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;int nzd(int a, int b) {&lt;br /&gt;   return ( b != 0 ? nzd(b, a % b) : a );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int nzs(int a, int b) {&lt;br /&gt;   return (a*b)/nzd(a,b);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;</description><link>http://codeperfection.blogspot.com/2008/11/blog-post.html</link><author>noreply@blogger.com (igormk)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-3746238826952558742</guid><pubDate>Thu, 04 Sep 2008 01:17:00 +0000</pubDate><atom:updated>2008-11-17T13:42:43.976-08:00</atom:updated><title>Ојлеров циклус</title><description>&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUVsuVk-WgVEXXjx5W0oPssM31zBQ1D_JpLOCPdhN38N1gKUaC4B_tLYvuCpGe74ajxoO03RFjIDx5OCdN_kdP_LJCFv7ohQKVE-e3eS9tj6aK4U8FSX2bCseazMDdtM3JiU3jJEsgQr8X/s1600-h/eulerian_grapg.JPG&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 307px; height: 320px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUVsuVk-WgVEXXjx5W0oPssM31zBQ1D_JpLOCPdhN38N1gKUaC4B_tLYvuCpGe74ajxoO03RFjIDx5OCdN_kdP_LJCFv7ohQKVE-e3eS9tj6aK4U8FSX2bCseazMDdtM3JiU3jJEsgQr8X/s320/eulerian_grapg.JPG&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5269745104132569442&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;Да се одреди дали еден граф има Ојлеров пат или циклус е лесно, се применуваат две правила.&lt;br /&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;Граф има Ојлеров циклус ако и само ако е поврзан (кога ќе ги извадиме сите темиња со степен 0) и секое теме има &quot;парен степен&quot;.&lt;/li&gt;&lt;li&gt;Граф има Ојлеров пат ако и само ако е поврзан и сите темиња освен две имаат парни степени&lt;/li&gt;&lt;li&gt;Во вториот случај, едно од двете темиња кое има непарен степен мора да биде почетно теме, додека другото е крајното теме.&lt;/li&gt;&lt;/ul&gt;&lt;div style=&quot;text-align: left;&quot;&gt;Основната идеја на алгоритмот е да се почне од некое теме во графот и да се одреди цуклус кој се враќа пак во истото теме. Сега, кога е додаден циклус (во спротивен редослед), алгоритмот гарантира дека сите ребра на сите темиња по тој пат се искористени. Ако постои некое теме по должината на тој пат што има ребро кое што не е искористено, тогаш алгоритмот наоѓа циклус што почнува во тоа теме што го користи тоа ребро и го вметнува тој циклус во моменталнио. Ова продолжува се додека сите ребра на сите темиња во оригиналниот циклус се искористени, па резултантниот циклус е Ојлеров.&lt;br /&gt;&lt;br /&gt;Да поедноставиме, за да се одреди Ојлеров циклус на граф, одбираме почетно теме и вршиме рекурзија. На секој рекурзивен чекор:&lt;br /&gt;&lt;/div&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;Ако темето нема соседи, тогаш го додаваме темето на циклусот и се враќаме&lt;/li&gt;&lt;li&gt;Ако темето има соседи, тогаш правиме листа на сите соседи и нив ги обработуваме (што вклучува нивно бришење од листата на темиња на кои треба да работиме) додека темето нема повеќе соседи&lt;/li&gt;&lt;li&gt;За да процесираме теме, го бришеме реброто помеѓу моменталното теме и неговиот сосед, вршиме рекурзија на соседот, и го додаваме моменталното теме на циклусот&lt;/li&gt;&lt;/ul&gt;&lt;div style=&quot;text-align: left;&quot;&gt;Овој алгоритам работи во O(m + n) време, каде m е бројот на ребра и n е бројот на темиња, ако се чува графот во &quot;листа на соседи&quot;.&lt;br /&gt;&lt;br /&gt;Литература: &lt;a href=&quot;http://http//ace.delos.com/usacogate&quot;&gt;USACO&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style=&quot;;font-family:Verdana,Tahoma,sans-serif,Arial,Lucida Sans,Gill Sans;font-size:100%;&quot;  &gt;&lt;/span&gt;</description><link>http://codeperfection.blogspot.com/2008/09/blog-post.html</link><author>noreply@blogger.com (igormk)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUVsuVk-WgVEXXjx5W0oPssM31zBQ1D_JpLOCPdhN38N1gKUaC4B_tLYvuCpGe74ajxoO03RFjIDx5OCdN_kdP_LJCFv7ohQKVE-e3eS9tj6aK4U8FSX2bCseazMDdtM3JiU3jJEsgQr8X/s72-c/eulerian_grapg.JPG" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-7465598655804873174</guid><pubDate>Tue, 15 Jul 2008 02:46:00 +0000</pubDate><atom:updated>2008-07-14T20:00:14.812-07:00</atom:updated><title>Google Code Jam</title><description>&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://code.google.com/codejam/images/logo/logo_image3.gif&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px;&quot; src=&quot;http://code.google.com/codejam/images/logo/logo_image3.gif&quot; alt=&quot;&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://code.google.com/codejam/&quot;&gt;Google Code Jam&lt;/a&gt; е алгоритамско натпреварување на кое може да учествува секој. Има примамливи награди, а и натпреварот е одлично организиран (претпоставувам бидејќи го организира Google, но до сега не сум учествувал). Значи на 16 јули ќе има квалификациска рунда каде што ќе се одберат најдобрите 500 кои ќе одат понатаму.&lt;br /&gt;&lt;br /&gt;Квалификациската рунда ќе трае 24 часа. Во правилата пишува дека ќе има од 4-6 задачи. Оние што ги дадоа за practice рундата ми се интересни, не се баш многу тешки, но за добар успех сепак треба рутина во кодирање.&lt;br /&gt;&lt;br /&gt;Им го препорачувам овој натпревар на сите кои што се разбираат од програмирање, и за почетници се разбира. Нема ништо да изгубат, туку само ќе добијат. Јас можеби ќе учествувам, но имам еден технички проблем кој се обидувам да го решам. Таму треба да се работи со датотеки и се чита влез од фајл, и излезот се испраќа до главниот сервер. Е сега не можам да се одлучам во кој програмски јазик да програмирам. Од кога научив Java пред 2-3 месеци заради codefu натпреварот тој ми стана омилен јазик за програмирање, само проблем е што не знам како да работам со датотеки. Втор омилен јазик ми е C++, го знам прилично добро овој јазик, но имам еден проблем кога читам од датотеки. Се надевам во брзо време ќе го решам ова. C го знам и може да ми послужи, но сепак ми е &quot;понапорен&quot; од C++. За Pascal нема ни да зборувам, него го баталив со завршувањето на Светската Олимпијада по Информатика. Значи ако го решам овој технички проблем со читање и запишување во датотеки учествувам на Google Code Jam. Да си ја пробам среќата.</description><link>http://codeperfection.blogspot.com/2008/07/google-code-jam.html</link><author>noreply@blogger.com (igormk)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4267540809652741503.post-8002276584656043095</guid><pubDate>Tue, 15 Jul 2008 02:13:00 +0000</pubDate><atom:updated>2008-07-14T20:00:49.319-07:00</atom:updated><title>Здраво</title><description>Здраво на сите што случајно или намерно ќе налетаат на мојот блог.&lt;br /&gt;&lt;br /&gt;Името на блогот е малку долго ама ми се допаѓа, интересно е. Инаку ќе пишувам на македонски и на англиски. Прво отворив блог на wordpress ама ме изнервира тоа што плугини не се дозволени од &quot;безбедносни причини&quot;. Сега за сега мислам дека blogspot ќе ми овозможи најдобар простор за искажување на тоа што сакам да го искажам.&lt;br /&gt;&lt;br /&gt;Инаку овој блог е наменет пред се за објавување на моите размислувања, истражувања, искуства во, околу и надвод од светот на компјутерите. Пред се ќе се фокусирам на алгоритмите како основа на информатиката. Исто така и ќе се осврнувам на новата технологија. Се надевам дека овој блог ќе биде интересно место на Интернет.&lt;br /&gt;&lt;br /&gt;Кој сум јас? Јас сум Игор Кулев, студент на ФЕИТ (или како си го викаме електро) прва година, всушност сега завршив прва. Имам искуство во натпревари по информатика и ме интересира компјутерската наука, логиката и вештачката интелигенција најмногу.</description><link>http://codeperfection.blogspot.com/2008/07/blog-post.html</link><author>noreply@blogger.com (igormk)</author><thr:total>0</thr:total></item></channel></rss>