猴子課堂:ISAP學習筆記

来源:https://www.cnblogs.com/zhangjianjunab/archive/2018/09/24/9694677.html
-Advertisement-
Play Games

學完了ISAP,感覺心情舒暢,畢竟ISAP比Dinic好一點。 說到底ISAP其實是Dinic(不熟悉Dinic的人去我的博客找猴子課堂 最大流與最小割(看看思想),已經置頂)優化版,熟悉的人知道Dinic是通過不斷分層來做的,但是,我們如果用打標記(貂蟬的標記)的方法就會快一些! 會快的原因就是因 ...


學完了ISAP,感覺心情舒暢,畢竟ISAP比Dinic好一點。

說到底ISAP其實是Dinic(不熟悉Dinic的人去我的博客找猴子課堂----最大流與最小割(看看思想),已經置頂)優化版,熟悉的人知道Dinic是通過不斷分層來做的,但是,我們如果用打標記(貂蟬的標記)的方法就會快一些!

會快的原因就是因為他省了很多分層的時間,使得他比Dinic要快不少,首先,我們先初始化一遍(從t開始搜,建個分層圖(不是說不用寬搜了嗎)),雖然過程中不用多次分層,但初始化分層,使得代碼要乾的事情少了不少(因為讓代碼通過自身調整標記要O(n^2)時間,但如果用寬搜初始化分層就讓時間縮短為O(n),也是十分不錯的呢!)

然後每次按分層規矩(註意,這裡以結尾為原點建分層圖,是由高的層流向比他低一層的層)找一條路徑(沒錯,你沒聽錯,就是單路增廣!),從起點出發:

流完後,然後回到起點,找另外一條流完,就結束了?

比如這張:

下麵一條可行路徑就因為———(兒童不宜)的關係流不過去了(分層有時會導致兩個相鄰點層數相同)。。。

所以,ISAP的精華!出來吧!

詢問?詢問什麼?就是找與他相連的點(邊要有流量)中層數最小的,之後,它就可以變身成比這個編號大一層的點,繼續為流量做貢獻!(在一個點找不到下一個點時,就調整這個點的標記)

改完之後:

就這樣解決了呢!(只需要在s的層數大於點數就可以退出了)

呵呵

上代碼:

不!不!不!太慢了!

我們會發現一件事,如果一種數字的編號消失,就永遠消失了,如果消失,路徑少一編號就不行了,也可以退出!(可以用num記錄每一編號的個數,在每次調整標記時判斷)

耶!一頓操作猛如虎!(這叫斷層優化)

證明(斷層優化):

設當前編號為x的數沒了,設y=x-1,那麼,編號為y的點有沒有可能變為x呢?首先,如果經過了x,那麼s的層數≥x,且這個為最短的路徑,也就說後面的s的編號都≥x,那麼每條路經中必須有個x。

但x沒了,也就需要一些點來與y的點連接變成x,但是,如果有的話,這些點的層數在作分層時,就已經等於x了(想想看,為什麼不可能小於x(其實就是懶得寫)),那麼路徑就不會產生斷層(矛盾)!

所以斷層優化成立,但是必須基於編號最小的基礎上!

講得好爛。。。

然後,上!代碼。。。

include

include

include

using namespace std;
struct node
{
int y,c,next,other;
}a[210000];int len,last[210000],n,m,st,ed;
void ins(int x,int y,int c)
{
len++;
a[len].y=y;a[len].c=c;a[len].next=last[x];last[x]=len;
len++;
a[len].y=x;a[len].c=0;a[len].next=last[y];last[y]=len;
a[len].other=len-1;a[len-1].other=len;
}//建邊
int h[210000]/層數/,num[210000]/斷層優化/,cur[210000]/弧優化/,qian[210000]/保留前一個點到達這裡的邊的編號/;
int list[210000],head,tail;
void bt()
{
head=1;tail=2;num[h[ed]=1]++;list[head]=ed;
while(head!=tail)
{
int x=list[head];
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y,kl=a[k].other;
if(a[kl].c>0 && h[y]==0)
{
num[h[y]=h[x]+1]++;
list[tail++]=y;
}
}
head++;
}
if(h[st]==0)h[st]=n+1;/判斷能不能到達終點/
}
int mymin(int x,int y){return x<y?x:y;}
int add()/流量/
{
int now=ed,ans=999999999;
while(now!=st)
{
ans=mymin(ans,a[qian[now]].c);
now=a[a[qian[now]].other].y;
}/找路徑上的最小流量/
now=ed;
while(now!=st)
{
a[qian[now]].c-=ans;a[a[qian[now]].other].c+=ans;
now=a[a[qian[now]].other].y;
}/減流/
return ans;
}
int findflow()
{
int ans=0,now=st;
bt();
while(h[st]<=n)
{
bool bk=true;
while(bk==true)/判斷走不走得通/
{
bk=false;
for(int &k=cur[now];k;k=a[k].next)//想想這的當前弧為何長這樣
{
int y=a[k].y;
if(a[k].c>0 && h[y]+1==h[now])
{
bk=true;
qian[y]=k;
now=y;
break;/記錄/
}
}
if(now==ed)
{
ans+=add();now=st;
}/增值/
}
int minn=n;
for(int k=last[now];k;k=a[k].next)
{
if(a[k].c>0)minn=mymin(minn,h[a[k].y]);
}//找層數
if((--num[h[now]])==0)break;//斷層優化
cur[now]=last[now];
num[h[now]=minn+1]++;//更改
if(now!=st)now=a[a[qian[now]].other].y;//想想為什麼這樣打(提示:從是不是最短的路徑上想)
}
return ans;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&st,&ed);
for(int i=1;i<=m;i++)
{
int x,y,c;scanf("%d%d%d",&x,&y,&c);
ins(x,y,c);
}
for(int i=1;i<=n;i++)cur[i]=last[i];
printf("%d\n",findflow());
return 0;
}
為什麼會快?

其實它比Dinic少了很多沒用的遞歸,讓每次找路徑都有作用,而且用標記省了bfs的時間,所以,只要不被惡意卡掉,ISAP整體上比Dinic要優秀!

註:上面的圖片侵權抱歉!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 高階組件 簡單來說,高階組件可以看做一個函數,且該函數接受一個組件作為參數,並返回一個新的組件。 我在之前的博客 "《閉包和類》" 中提到一個觀點,面向對象的好處就在於,易於理解,方便維護和復用。 其實高階組件,也是為了更好地復用之前的組件。它可以理解為,基礎組件通過包裹處理,生成一個適應某些場景的 ...
  • JavaScript流程式控制制語句腦圖 圖片是從網上找來的,在這記錄一下,以備後面需要的時候查找方便。 JavaScript通過規定的語句讓有條件的按照一定的方式執行。 分為:迴圈語句 while do-while for for-in 跳轉語句 return break continue 選擇語句 ...
  • JavaScript 中的 ajax 很早之前就有一個詬病————複雜業務下的 callback 嵌套的問題。promise 正是 js 中解決這一問題的鑰匙。 接下來我們在react項目中應用到的fetch 就用到了最新的 promise。 那我們如何在react項目中應用fetch呢? 第一步: ...
  • 前言 此系列是針對springboot的啟動,旨在於和大家一起來看看springboot啟動的過程中到底做了一些什麼事。如果大家對springboot的源碼有所研究,可以挑些自己感興趣或者對自己有幫助的看;但是如果大家沒有研究過springboot的源碼,不知道springboot在啟動過程中做了些 ...
  • 7 Anonymous inner class (視頻下載) (全部書籍) 馬克-to-win:有時如此簡單,都沒有必要清清楚楚明確出類名,用一下就完,就用匿名內部類。註意: 下麵的new FigureMark_to_win(){。。。。};的語法形式。它和以往的new FigureMark_to_ ...
  • 在Ubuntu18.04中,傳統的配置/etc/network/interfaces已無用 新方法:修改 配置如下: 重啟網路 如果網路不正常可以使用: 測試一下遠程連接 ...
  • 什麼是靜態內部(Static Inner)類,語法要註意什麼? ...
  • 什麼是實例內部類 Instance inner class有什麼語法? ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...