【圖論】割點、橋、雙連通

連通分量

個數可以通過一次BFS或者DFS得到


割點和橋

可以枚舉刪除每一個點或者每一條邊,判斷連通分量個數是否增加


更好的方法

?

該算法是R.Tarjan發明的。對圖深度優先搜索,定義DFS(u)為u在搜索樹(以下簡稱為樹)中被遍歷到的次序號。定義Low(u)為u或u的子樹中能通過非父子邊追溯到的最早的節點,即DFS序號最小的節點。

一個頂點u是割點,當且僅當滿足(1)或(2)?

(1) u為樹根,且u有多于一個子樹。?

(2) u不為樹根,且滿足存在(u,v)為樹枝邊(或稱父子邊,即u為v在搜索樹中的父親),使得DFS(u)<=Low(v)


一條無向邊(u,v)是橋,當且僅當(u,v)為樹枝邊,且滿足DFS(u)<Low(v)

void dfs(int u,int fa)
{int child=0;pre[u]=low[u]=++tim;for(int e=fst[u];e!=-1;e=nxt[e]){int v=s[e].y;if(!pre[v]){child++;dfs(v,u);low[u]=min(low[u],low[v]);if(low[v]>=pre[u])cut[u]++;if(low[v]>pre[u])bridge[e]=1;}elseif(pre[v]<pre[u] && v!=fa)	//v!=falow[u]=min(low[u],pre[v]);}if(fa<0&&child==1)cut[u]=0;
}


需要注意的是:

1.如果i是root,那么去掉i后,連通分量個數增加cut[i]-1個。如果i不是root,那么連通分量增加cut[i]個

2.無向圖 ?bridge[e]=1 ?bridge[e+1]同樣應標注為1(bridge[e-1])


雙連通

?

雙連通分點雙聯通和邊雙聯通

對于一個連通圖,若任意兩點至少存在兩條“點不重復”的路徑,則此連通圖是點-雙連通的,意味著任意的兩條邊都是在同一個簡單環上,即內部無割頂。點-雙連通的極大子圖叫做雙連通分量或塊。定理:不同雙聯通分量最多只有一個公共點,且它一定是割頂,任意割頂都是至少兩個不同雙連通分量的公共點。

對于一個連通圖,若任意兩點至少存在兩條“邊不重復”的路徑,則此連通圖是邊-雙連通的,意味著只需要每條邊都至少在一個簡單環中,即所有邊都不是橋。邊-雙連通的極大子圖叫做邊-雙連通分量,除了橋不屬于任何邊-雙連通分量之外,其他每條邊恰好屬于一個邊-雙連通分量,而且把所有橋刪除之后,每個連通分量對應原圖中的一個邊-雙連通分量。


對于點雙連通分支,實際上在求割點的過程中就能順便把每個點雙連通分支求出。建立一個棧,存儲當前雙連通分支,在搜索圖時,每找到一條樹枝邊或后向邊(非橫叉邊),就把這條邊加入棧中。如果遇到某時滿足DFS(u)<=Low(v),說明u是一個割點,同時把邊從棧頂一個個取出,直到遇到了邊(u,v),取出的這些邊與其關聯的點,組成一個點雙連通分支。割點可以屬于多個點雙連通分支,其余點和每條邊只屬于且屬于一個點雙連通分支。



對于邊雙連通分支,求法更為簡單。只需在求出所有的橋以后,把橋邊刪除,原圖變成了多個連通塊,則每個連通塊就是一個邊雙連通分支。橋不屬于任何一個邊雙連通分支,其余的邊和每個頂點都屬于且只屬于一個邊雙連通分支。

有重邊的 邊-雙連通分量 應尤其注意,因為重邊也算不同的邊。解決方案是用邊判斷,而不是利用v!=fa判斷能否由pre[v]更新low[u]

void dfs(int u,int fa)
{tim++;low[u]=pre[u]=tim;for(int e=fst[u];e!=-1;e=nxt[e]){int w=e;if (e%2)w++;else w--;int v=s[e].y;if(!pre[v]){dfs(v,e);low[u]=min(low[u],low[v]);if (low[v]>pre[u])bridge[e]=bridge[w]=1;}else//if(pre[v]<pre[u] && v != fa)if (pre[v]<pre[u] && (e!=fa && w!=fa))low[u]=min(low[u],pre[v]);}
}

?

void dfs(int u)
{tim++;pre[u]=low[u]=tim;for(int e=fst[u];e!=-1;e=nxt[e]){int w=e;if(w%2)w++;else w--;int v=s[e].y;if(!pre[v]){flag[e]=flag[w]=1;dfs(v);low[u]=min(low[u],low[v]);if(low[v]>pre[u])cnt[e]=cnt[w]=1;}else if(pre[v]<pre[u]&&!flag[e])  //判斷邊而不是判斷點 {flag[e]=flag[w]=1;low[u]=min(low[u],pre[v]);}}
}



構造雙連通圖

?

一個有橋的連通圖,如何把它通過加邊變成邊雙連通圖?方法為首先求出所有的橋,然后刪除這些橋邊,剩下的每個連通塊都是一個雙連通子圖。把每個雙連通子圖收縮為一個頂點,再把橋邊加回來,最后的這個圖一定是一棵樹,邊連通度為1。

統計出樹中度為1的節點的個數,即為葉節點的個數,記為leaf。則至少在樹上添加(leaf+1)/2條邊,就能使樹達到邊二連通,所以至少添加的邊數就是(leaf+1)/2。具體方法為,首先把兩個最近公共祖先最遠的兩個葉節點之間連接一條邊,這樣可以把這兩個點到祖先的路徑上所有點收縮到一起,因為一個形成的環一定是雙連通的。然后再找兩個最近公共祖先最遠的兩個葉節點,這樣一對一對找完,恰好是(leaf+1)/2次,把所有點收縮到了一起。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int m,tn,n;
struct path{int x,y;}s[20001];
int fst[20001],nxt[20001];
bool bridge[20001];
int pre[5001],low[5001];
int tim,part,x,y;
int hash[5001],out[5001];void dfs(int u,int fa)
{tim++;low[u]=pre[u]=tim;for(int e=fst[u];e!=-1;e=nxt[e]){int w=e;if (e%2)w++;else w--;int v=s[e].y;if(!pre[v]){dfs(v,e);low[u]=min(low[u],low[v]);if (low[v]>pre[u])bridge[e]=bridge[w]=1;}else//if(pre[v]<pre[u] && v != fa)if (pre[v]<pre[u] && (e!=fa && w!=fa))low[u]=min(low[u],pre[v]);}
}void makeside(int x,int y)
{n++;s[n].x=x;s[n].y=y;nxt[n]=fst[x];fst[x]=n;
}void color(int i)
{hash[i]=part;for(int e=fst[i];e!=-1;e=nxt[e])if (!bridge[e]&&!hash[s[e].y])color(s[e].y);
}void print()
{int z=0;for(int e=1;e<=n;e++)if(bridge[e]){out[hash[s[e].x]]++;out[hash[s[e].y]]++;}for(int i=1;i<=part;i++)if(out[i]==2)z++;cout<<(z+1)/2<<endl;
}int main()
{while(scanf("%d%d",&m,&tn)==2){memset(fst,-1,sizeof(fst));memset(nxt,-1,sizeof(nxt));memset(bridge,0,sizeof(bridge));memset(hash,0,sizeof(hash));memset(out,0,sizeof(out));memset(pre,0,sizeof(pre));memset(low,0,sizeof(low));n=part=tim=0;for(int i=1;i<=tn;i++){scanf("%d%d",&x,&y);makeside(x,y);makeside(y,x);}for(int i=1;i<=m;i++)if(!pre[i])dfs(i,-1);for(int i=1;i<=m;i++)if(!hash[i]){part++;color(i);}print();}		return 0;
}


見題目:

HOJ

1007 SPF

1098 NetWork

1789 Electricity

2360 Redundant Paths

?

POJ

3117?Redundant Paths

3352?Road Construction



參考:

https://www.byvoid.com/blog/biconnect

http://blog.csdn.net/z635457712a/article/details/8229113

http://blog.csdn.net/lyy289065406/article/details/6762370


?

轉載于:https://www.cnblogs.com/abgnwl/p/6550352.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/375478.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/375478.shtml
英文地址,請注明出處:http://en.pswp.cn/news/375478.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

奇酷手機顯示Log

1、在桌面點擊撥號&#xff0c;在撥號盤輸入“*20121220#”&#xff0c;進入工程模式;2、看到日志輸出等級&#xff0c;點進去 Log print enable 選 enable Java log level 選 LOGV C and C log level 選 LOGV Kernel log level 選 KERN_DEBUG3、完畢 參考網址&#xff1a;http…

getCanonicalPath getAbsolutePath區別

1、在winows環境下它們的區別是 &#xfeff;&#xfeff;getCanonicalPath是標準路徑&#xff0c;沒有特殊字符&#xff0c;getAbsolutePath是有特殊字符的 2、在AIX系統中它們的區別&#xff1a; 首先編譯&#xff1a;javac com/ai/test/BugTest.java 然后運行&#xff1a;ja…

Hbase與hive整合

//hive與hbase整合create table lectrure.hbase_lecture10(sname string, score int) stored by org.apache.hadoop.hive.hbase.HBaseStorageHandler whth serdeproperties("hbase.columns.mapping" :key,cf1:score)tblproperties("hbase.table.name" &q…

C++實現一個http服務器

一個簡單的博客后端服務器 github地址&#xff0c;持續更新 設計參考 #define MYSQLPP_MYSQL_HEADERS_BURIED #include "httplib.h" #include "rapidjson/document.h" #include <mysql/mysql.h> #include <iostream> #include <string>…

KMP算法的java實現

package com.trs.utils;public class KMPStr {/** 在KMP算法中&#xff0c;最難求的就是next函數&#xff0c;如何理解next函數是一個難題&#xff0c;特別是knext[k]&#xff0c;這里* 需要指出的是當p[i]!p[j]時&#xff0c;我們只有通過回溯將k的值逐漸減小&#xff0c;貌似…

線段分割法實現微信搶紅包

無意間看到的一種實現搶紅包的方法&#xff0c;于是用C實現了一下。 將一個紅包分成 n 份 具體的思路是&#xff0c;將一個紅包看作是一個線段&#xff0c;線段的長就是紅包總金額&#xff0c;然后在這個線段上隨機切 n-1 刀&#xff0c;分成 n 份&#xff0c;然后搶紅包的人依…

JAVA多線程和并發基礎面試問答(轉載)

JAVA多線程和并發基礎面試問答 原文鏈接&#xff1a;http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-answers/ 多線程和并發問題是Java技術面試中面試官比較喜歡問的問題之一。在這里&#xff0c;從面試的角度列出了大部分重要的問題&#xff0c…

Linux的學習--crontab

之前了解過一點crontab&#xff0c;前段時間比較閑&#xff0c;就熟悉了一下&#xff0c;今天總結記錄一下。 crontab命令常見于Unix和類Unix的操作系統之中&#xff0c;用于設置周期性被執行的指令。該命令從標準輸入設備讀取指令&#xff0c;并將其存放于"crontab"…

C++雪花算法實現

看來一下雪花算法的實現方法&#xff0c;用 c試著實現了一下&#xff0c;這里僅僅是實現了算法的流程&#xff0c;但是具體的細節&#xff0c;如并發、多線程訪問等等沒有具體考慮。 雪花算法的簡單講解參考 #include <sys/select.h> #include <iostream> #includ…

CAlayer層的屬性

iOS開發UI篇—CAlayer層的屬性 一、position和anchorPoint 1.簡單介紹 CALayer有2個非常重要的屬性&#xff1a;position和anchorPoint property CGPoint position; 用來設置CALayer在父層中的位置 以父層的左上角為原點(0, 0) property CGPoint anchorPoint; 稱為“定位點”、…

Window Linux下實現指定目錄內文件變更的監控方法

轉自&#xff1a;http://qbaok.blog.163.com/blog/static/10129265201112302014782/ 對于監控指定目錄內文件變更&#xff0c;window 系統提供了兩個未公開API&#xff1a;SHChangeNotifyRegister SHChangeNotifyDeregister 分別用于注冊Notify以及監視。 同時&#xff0c;還提…

Odoo9發行說明

2015年10月1日&#xff0c;期待已久的Odoo9正式發布。本文是Odoo9正式版發行說明&#xff0c;基于官網資料翻譯。 譯者: 蘇州-微塵原文地址&#xff1a;https://www.odoo.com/page/odoo-9-release-notes譯文地址&#xff1a;http://blog.csdn.net/wangnan537/article/details/4…

揭秘史上最完美一步到位的搭建Andoriod開發環境

Windows環境下Android開發環境搭建雖然不難而且網上資料眾多&#xff0c;但是眾多資料如出一折 忽略了很多細節&#xff0c;最終還是沒能達到滿意效果。 基本步驟如下&#xff1a;JDK安裝、環境變量配置、Eclipse下載、AndoriodSDK下載安裝、下載配置ADT但是到這里還不算完美搞…

基于OpenCv的人臉檢測、識別系統學習制作筆記之二

在網上找到了一個博客&#xff0c;里面有大量內容適合初學者接觸和了解人臉檢測的博文&#xff0c;正好符合我目前的學習方面&#xff0c;故將鏈接放上來&#xff0c;后續將分類原博客的博文并加上學習筆記。 傳送門&#xff1a; http://blog.sina.com.cn/s/articlelist_160256…

URL 化

URL化。編寫一種方法&#xff0c;將字符串中的空格全部替換為%20。假定該字符串尾部有足夠的空間存放新增字符&#xff0c;并且知道字符串的“真實”長度。&#xff08;注&#xff1a;用Java實現的話&#xff0c;請使用字符數組實現&#xff0c;以便直接在數組上操作。&#xf…

第一章 00 StringUtil.cpp和StringUtil.hh分析

1 /*2 * StringUtil.hh3 *4 * Copyright 2002, Log4cpp Project. All rights reserved.5 *6 * See the COPYING file for the terms of usage and distribution.7 */8 頭文件的說明&#xff0c;以及與版權相關的說明一般都會放置在文件的開始位置 9 #ifndef _LOG4CPP_STR…

【SQL】服務器環境下的SQL

一、大型數據庫的三層體系結構 web服務器&#xff1a;比如在淘寶頁面上&#xff0c;輸入“牛肉干”&#xff0c;就是web服務器來處理&#xff0c;提交給應用服務器。 應用服務器&#xff1a;在獲取到“牛肉干”這個請求后&#xff0c;應用服務器決定如何匯集結果&#xff0c;并…

【置頂】全局變量的好處與壞處

近日在做項目的過程中對plsql的使用非常多&#xff0c;主要是編寫存儲過程實現業務邏輯。但是在coding的過程中遇到非常奇怪的問題。 問題是&#xff1a;在package包頭中定義了一個變量&#xff0c;current_time : sysdate,然后在procedure使用這個定義的變量&#xff0c;直接i…

三個線程按順序輸出數字

當 n 3N 時&#xff0c;線程1輸出 當 n 3N 1 時&#xff0c;線程2輸出 當 n 3N 2 時&#xff0c;線程3輸出 最終的輸出為 0、1、2、3、4、5、6、7、8、10 #include <iostream> #include <thread> #include <mutex> #include <condition_variable&g…

TextView實現自動滾動滾動.

必須有要四個屬性: android:ellipsize"marquee"; android:focusable"true";android"focusableInTouchMode"true";android:singleLine"true"; <TextViewandroid:layout_width"fill_parent"android:layout_height&quo…