學習乙個朱劉演算法

2021-08-05 23:53:46 字數 2499 閱讀 2736

什麼是最小樹形圖?相信大家如果會過來看這篇文章,想必也應該對最小生成樹有所了解的,最小生成樹求的是無向圖的一顆生成樹的最小權值。我們的最小樹形圖就是來解決乙個有向圖的一顆生成樹的最小權值,對於度娘來說,最小樹形圖是這樣定義的:最小樹形圖,就是給有向帶權圖中指定乙個特殊的點root,求一棵以root為根的有向生成樹t,並且t中所有邊的總權值最小。

通解最小樹形圖的一種演算法是是2023年朱永津和劉振巨集提出的複雜度為o(ve)的演算法:朱、劉演算法。

今天我們就來**一下最小樹形圖的問題。

大題上完整的朱、劉演算法是由四個大步驟組成的:

1、求最短弧集合e

2、判斷集合e中有沒有有向環,如果有轉步驟3,否則轉4

3、收縮點,把有向環收縮成乙個點,並且對圖重新構建,包括邊權值的改變和點的處理,之後再轉步驟1。

4、展開收縮點,求得最小樹形圖。

因為我們acm一般情況下都是在考察隊最小樹型圖的權值問題,所以一般省略步驟4,對於其環的權值和在中間處理過程中就可以處理完畢。所以我們這裡就不多討論第四個點了。

我們分步處理、

1、首先我們先求最短弧集合e,對於當前圖如果有n個點(乙個有向環的收縮點算作乙個點),我們就要選出n-1個點,確定其入邊的最短邊,由其組成的乙個集合我們就叫做最短弧集合e,如果我們列舉到某乙個點的時候,它沒有入邊,那麼說明不存在最小樹形圖,所以這個時候演算法結束,回到主函式。

**實現:

for(int i=1; i<=n; i++)if(i!=u&&!flag[i])//u作為圖的根節點,flag【i】為1的情況就是表示這個點在某個有向環裡邊,並且他不是這個有向環的代表點(縮點)  

if(pre[i]==i)return -1;//如果當前列舉到的點i沒有入邊,那麼就不存在最小樹形圖(因為一顆樹是要所有節點都是連通的啊)

}

2、然後我們對集合e中的邊進行判斷,判斷是否有有向環。剛剛的**實現裡邊有乙個前驅節點的儲存,所以在這個部分,我們直接一直向前列舉前驅點即可,如果列舉的前驅點最終能夠列舉到根節點,那麼這一部分就不存在有向環,否則就存在,對於每乙個點都進行向前列舉即可。

int i;  

for(i=1; i<=n; i++)

}

3、如果有有向環呢,我們需要對有向環進行縮點,既然我們是列舉到節點i的時候發現有有向環,我們不妨把有向環裡邊的點都收縮成點i。對於收縮完之後會形成乙個新的圖,圖的變化規律是這樣的:

上圖變換成語言描述:如果點u在環內,如果點k在環外,並且從k到u有一條邊map【u】【v】=w,並且在環內還有一點i,使得map【i】【k】=w2,辣麼map【k】【收縮點】=w-w2;

基於貪心思想,對於環的收縮點i和另外一點k(也在環內),對於環外一點j,如果map【k】【j】

int j=i;  

memset(vis, 0, sizeof(vis));

do

while(j!=i);

flag[i] = false; // 環縮成了點i,點i仍然存在

4、處理收縮點後形成的圖:

for(int k=1; k<=n; ++k)if(vis[k])  // 在環中點點,剛剛在收縮點的時候,已經把在環中的點進行標記了。  

}

處理完4之後,我們就回到步驟1,繼續找最小弧集e,最後找到了乙個沒有環的最小弧集e之後,對於沒有弧的集合e中的所有邊(包括能將收縮點展開的邊)就是我們要求的最小樹形圖的邊集。

因為我們acm一般求的都是最小樹形圖的權值,所以我們一般不需要展開收縮點,在處理環的時候,直接將其邊權值記錄下來就好,當找到乙個沒有環的集合e的時候,對其中的最後邊權值進行加和即可,對於最後這部分的加權,**實現:

if(i>n)//這塊**是緊接著**2之後的部分,如果列舉了所有點i都沒有發現有向環,辣麼就是找到了這個最終集合。  

完整的朱、劉演算法**實現(沒有展開收縮點的):

void init()//不能少了初始化的內容  

} double directed_mst(int u)//u表示根節點

//判斷e是否有環

int i;

for(i=1; i<=n; i++)

} if(i>n)

//有環,進行收縮,把整個環都收縮到乙個點i上。

int j=i;

memset(vis, 0, sizeof(vis));

do

while(j!=i);

flag[i] = false; // 環縮成了點i,點i仍然存在

//收縮點的同時,對邊權值進行改變

for(int k=1; k<=n; ++k)if(vis[k]) // 在環中點點

學習筆記 朱劉演算法

樹形圖 最小樹形圖問題 找出總邊權和最小的樹形圖 朱劉演算法解決最小樹形圖問題。對於除根外每個點,找出該點入邊中權值最小的邊,把權加到答案中。判斷選出的邊是否存在環。若無環,退出,找到最小樹形圖,若有環,繼續執行步驟 3。將所有環縮點,構造乙個新圖,對於舊圖的每條邊 對於每個環而言,至少去掉一條邊。...

F Teen Girl Squad 朱劉演算法

f teen girl squad 題目主要是最小樹形圖,用朱劉演算法求解。include include include include using namespace std const int inf 0x3f3f3f3f const int maxn 1005 struct nede edg...

hdu4966 朱劉演算法

題意 輸入n門課,m條路,然後n個整數,表示這n門課要修到的最高等級,m行路每行5個數 a d1 b d2 x 表示的意思是從要花x元錢直接公升級到 b門課的d2等級的前提 是你的a課 要到打d1等級。要你求 將所有課程等級過完的最小花費。思路 將每門課的每個等級看成乙個點,每個點都在圖中,每個點只...