=====الگوریتم push relabel===== برای بهتر فهمیدن این الگوریتم قضیه شار بیشینه و برش کمینه را مطالعه کنید. ====الگوریتم==== ===نیم شار=== اگر یادتان باشد در شار ورودی و خروجی هر راس به جز ریشه و منبع باید برابر باشند. در این جا ما نیم شار را تعریف می‌کنیم که فرقش با شار این است که ورودی باید بیشتر یا مساوی خروجی باشد. یعنی هر راس مقداری سرریز دارد که به آن excess نیز گفته می‌شود. ===ارتفاع رئوس=== در این الگوریتم به هر راس ارتفاعی نسبت می‌دهیم که در ابتدا ارتفاع همه راس‌ها به جر منبع صفر است و ارتفاع منبع $|V|$ می‌باشد. ارتفاع راس منبع و مقصد همواره ثابت است. ارتفاع راس های درخت در یک مرحله درست است اگر شرط زیر برقرار باشد: \\ اگر از راس u به راس v بتوان شار فرستاد‌ (ظرفیت یال تکمیل نباشد)‌ آنگاه $h[u]\le h[v]+1$\\ ===تابع push=== این تابع دو ورودی میگیرد (مانند u و v) به شرطی که اولن ارتفاع راس u بیشتر از v باشد و این که راس u مقدار سرریز داشته باشد و بتواند توسط جهت u به v مقداری از این سرریز را به راس v منتقل کند. تابع push حداکثر مقداری که می‌تواند را منتقل می‌کند. اگر تابع push از تمام ظرفیت یال استفاده کند آن یال را مسدود شده می‌نامیم. ===تابع ‌relabel=== این تابع در ورودی یک راس میگیرد که سرریز دارد و شرایط push را با هیچ راس دیگری ندارد. ارتفاع آن راس را تا جایی بالا می‌برد که قابلیت push با راس دیگری را داشته باشد. ===طریقه استفاده=== الگوریتم push relabel به سادگی میگوید هر بار عملیات push یا relabel می‌توان جایی انجام داد آن را انجام بده. برای پیاده سازی راحت تر میتوان روی راس ها هر بار پیمایش کرد و اگر راسی سرریز دارد اگر میشود push کرد مقدار سرریز را در غیر این صورت آن راس را relabel میکنیم. ====اثبات درستی==== ابتدا بررسی می‌کنیم اگر الگوریتم تمام شود شار بیشینه را به ما می‌دهد یا خیر. برای این کار از چند لم استفاده می‌کنیم :‌\\ ===لم ۱=== پس از هر عملیات push و relabel ارتفاع راس ها مقداری درست می‌مانند. ===اثبات=== به وضوح عملیات push این شرایط را به هم نمیزند چون روی ارتفاع بالاتر به پایین‌تر انجام می‌شود. عملیات relabel نیز نمی‌تواند مشکلی ایجاد کند چرا که از آنجا که وقتی یک راس را می‌خواهیم relabel کنیم شرایط push با هیچ راسی با ارتفاع پایین تر را نخواهد داشت و پس از relabel فقط شرایط push با یک ارتفاع پایین‌ترش را می‌تواند داشته باشد. ===لم ۲=== اگر الگوریتم تمام شود شار داده شده بیشینه است. ===اثبات=== برای این کار کافی‌ست نشان دهیم مسیر افزایشی‌ای نمی‌تواند وجود داشته باشد. فرض کنید مسیری از راس منبع به مقصد وجود دارد. آن مسیر را با $v_1, v_2, ..., v_k$ نشان می‌دیهم به طوری که $v_1$ راس منبع و $v_k$ راس مقصد باشد. طبق تعریف ارتفاع درست اگر ارتفاع راس ها درست باشد میدانیم $h[v_1]\le h[v_2]+1$ همچنین میانیم به ازای هر $i$ ($1\le i0}h[u]$ حال با استفاده از تغییرات $\phi$ نشان می‌دهیم این مقدار درست است. اگر عملیات relabel انجام دهیم از آنجا که ارتفاع راس زیاد می‌شود مقدار $\phi$ را حداکثر $2n$ واحد زیاد می‌کند. از انجا که ارتفاع راس‌ها حداکثر $2n$ می‌شود پس در مجموع relabel ها مقدار این عدد را $4n^2$ زیاد می‌کند. حال تاثیر push های مسدود کننده را در نظر می‌گیریم. هر ‌‌‌push مسدود کننده حداکثر به اندازه راس پایین‌تر به عددمان اضافه می‌کند پس در کل $4ev^2$ می‌شود. حال هر بار push غیر مسدود کننده می‌دهیم حتمن سرریز راس بالایی صفر می‌شود و سرریز راس پایین تر ممکن است اضافه شود پس $\phi$ حداقل یک واحد کم می‌شود. پس حداکثر به اندازه جوابی که گفتیم تغییر می‌کند. ====تحلیل زمانی==== برای تحلیل زمانی کافی است به لم های قسمت قبل نگاه کنیم. در مجموع کار هایی که می‌‌کنیم از $O(v^2e)$ می‌شود. ====پیاده‌سازی==== در پیاده‌سازی این الگوریتم می‌توان فرض کرد یال چندگانه و دوطرفه وجود دارد، اما برای راحتی برنامه فرض می‌کنیم فقط در یک جهت وجود دارد. ====کد==== #include #include using namespace std; const int maxn = 100; // agar tewdad yal ha km bashad ta 300 niz javab midahad int n, m, s, t, excess[maxn], flow[maxn][maxn], capacity[maxn][maxn], h[maxn]; vector G[maxn]; void push(int u, int v){ int amount = min(excess[u] , capacity[u][v]-flow[u][v]); excess[u] -= amount; excess[v] += amount; flow[u][v] += amount; flow[v][u] -= amount; } void relabel(int u){ int newheight = 2*n-1; for(int v=0; v 0) newheight = min(newheight, h[v]+1); } h[u] = newheight; } int main(){ cin >> n >> m >> s >> t; s--, t--; for(int i=0; i> u >> v >> cap; u--, v--; G[u].push_back(v); G[v].push_back(u); capacity[u][v] = cap; } for(int i=0; i 0){ next = true; for(int i=0; i h[v]) push(u,v) ; // agar available nabashad hichi push nemishavad } if(excess[u] > 0) relabel(u); // agar excess hanooz mosbat bood digar pushi nadarim } } cntinue = next; } cout << excess[t] << endl; // dar in ja excess[t] andaze shar bishine ast zira hich gah t ra push nemikonim return 0; }