縮點(有向圖的強連通分量)學習筆記

縮點(有向圖的強連通分量)學習筆記

1.什么是強連通分量?:

有向圖強連通分量:在有向圖G中,如果兩個頂點vi,vj間(vi>vj)有一條從vi到vj的有向路徑,同時還有一條從vj到vi的有向路徑,則稱兩個頂點強連通(strongly connected)。如果有向圖G的每兩個頂點都強連通,稱G是一個強連通圖。有向圖的極大強連通子圖,稱為強連通分量(strongly connected components)。——度娘

顯然正確,但是文縐縐的又難懂

其實就是有一大團點,它們之間可以互相到達,且沒有其它的點與它們互可到達,那么這一大團點就是有向圖的一個強聯通分量。

一個強連通分量可以看作一個或幾個環拼接在一起。

如:

2.如何操作?:

首先對于整個有向圖進行dfs,若dfs樹中存在子樹有到達父親節點,從父親到這個點則都可互相到達,這些點有可能與父親原屬的強連通圖合并,也有可能成為新的一個強連通分量。

如上圖。

所以我們判斷一個點是否在一個強連通分量中,就用它是否能到達dfs序比他小的點。

但我們如何將一個強連通分量的點記錄呢?

答:用一個棧儲存,遇到一個不能到達dfs序比他小的點的點,就將棧里的點都標記為一個新的強連通分量,再清空棧(一個點我們也看作一個強連通分量)。

我們用dfn數組記錄dfs序,low數組記錄能到達的點最小的dfs編號。

對于每一個點,需要用它的兒子的low來更新自己的low,如上圖中的2號點;

然而,若有連向父親的邊呢?是不是直接用父親的dfn來更新自己的low?

當然是對的!!!(作者就曾經錯在這里,曾今以為是對的,但打模板時錯了,改了兩處,結果以為是因為將dfn改為low才對的,后面發現不是,果然我還是太蒟蒻了qaq~~~~~

在tarjan算法中,都是用父親的dfn來更新自己的low,

但在有向圖中,若自己的父親有連向祖父等祖宗,那么自己和祖宗在同一個強連通分量;

而在無向圖中,則屬于兩個強連通分量。

如:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

其中,1、2、3、4、5互可到達,只有dfn[1]==low[1],都是一個強連通分量。

? ? ? ? ? ?

此時,用low來更新錯誤

?

還有,注意:對于已經屬于一個強連通分量的點,不能用它的low來更新連向它的點

? ? ? ?

所以,low[5]為5。

?

 1 void tarjan(int u)//當前點
 2 {
 3     low[u]=dfn[u]=++deep; x[++top]=u; v[u]=1;
 4     for(int i=head1[u];i;i=e[i].nxt)
 5     {
 6         if(!dfn[e[i].to]) tarjan(e[i].to),low[u]=min(low[u],low[e[i].to]);//連向兒子的邊
 7         else if(v[e[i].to]) low[u]=min(low[u],low[e[i].to]);//連向父親且不屬于一個強連通分量
 8     }
 9    if(dfn[u]==low[u])//找到一個強連通分量
10    {
11         num[u]=++tot; v[u]=0;
12         while(x[top]!=u) v[x[top]]=0,num[x[top]]=tot,--top;
13         --top;
14      }
15 }
16 int main()
17 {
18     for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
19     return 0;
20 }

?

?

?

最后,模擬一個圖的tarjan過程:

?

一共有一個強連通分量:1.{1,2,3,4,5,6,7,8,9}。

u=1:dfn[1]=1,++top,x[1]=1,tarjan(8);

u=8:dfn[8]=2,++top,x[2]=8,tarjan(9);

u=9:dfn[9]=3,++top,x[3]=9,low[9]=1;

u=8:low[8]=1;

u=1:tarjan(2);

u=2:dfn[2]=4,++top,x[4]=2,tarjan(3);

u=3:dfn[3]=5,++top,x[5]=3,tarjan(4);

u=4:dfn[4]=6,++top,x[6]=4,low[4]=low[2]=4;

u=3:low[3]=low[4]=4;

u=2:low[2]=4,tarjan(5);

u=5:dfn[5]=7,++top,x[7]=5,tarjan(6);

u=6:dfn[6]=8,++top,x[8]=6,tarjan(7);

u=7:dfn[7]=9,++top,x[9]=7,low[7]=1;

u=6:low[6]=1;

u=5:low[5]=1;

u=2:low[2]=1;

u=1:dfn[1]==low[1]=1→++tot,將x[1]到x[9]標記為tot=1,top=0;

結束。

3.縮點:

將每個強聯通分量看作一點,將所有連向強聯通分量內的點連向這個強聯通分量。

 1 int main()
 2 {
 3     n=read(); m=read();
 4     for(int i=1;i<=n;++i) w1[i]=read();
 5     for(re int i=1;i<=m;++i) t1=read(),t2=read(),add(t1,t2,e,head1);
 6     cnt=0;
 7     for(int i=1;i<=n;++i)
 8     {
 9         w2[num[i]]+=w1[i];
10         for(int j=head1[i];j;j=e[j].nxt) if(num[i]!=num[e[j].to]) add(num[i],num[e[j].to],f,head2),++rd[num[e[j].to]];
11     }
12     return 0;
13 }

洛谷P3387 【模板】縮點

題目背景

縮點+DP

題目描述

給定一個n個點m條邊有向圖,每個點有一個權值,求一條路徑,使路徑經過的點權值之和最大。你只需要求出這個權值和。

允許多次經過一條邊或者一個點,但是,重復經過的點,權值只計算一次。

輸入輸出格式

輸入格式:

?

第一行,n,m

第二行,n個整數,依次代表點權

第三至m+2行,每行兩個整數u,v,表示u->v有一條有向邊

?

輸出格式:

?

共一行,最大的點權之和。

?

輸入輸出樣例

輸入樣例#1:?
2 2
1 1
1 2
2 1
輸出樣例#1:?
2

說明

n<=10^4,m<=10^5,0<=點權<=1000

算法:Tarjan縮點+DAGdp

題解:

當進入一個強連通分量時,肯定將這個強連通分量都走一遍,所以縮點,變為一個DAG(有向無環圖),然后按拓撲序dp,每個點的答案為所有能到達它的點的答案的最大值+自己的點值,輸出所有點中答案的最大值。

用每個點的答案更新它所能到達的所有點的答案。

代碼如下:

 1 #include<bits/stdc++.h>
 2 #define re register
 3 using namespace std;
 4 const int N=10006,M=100006;
 5 int n,m,t1,t2,w1[N],w2[N],num[N],cnt=0,head1[N],t,tot=0,head2[N],x[N],dfn[N],low[N],ans[N],maxa=-1,rd[N],deep=0,top=0,v[N];
 6 struct edge
 7 {
 8     int to,nxt;
 9 }e[M],f[M];
10 inline void add(int u,int v,edge a[],int head[]){a[++cnt].to=v,a[cnt].nxt=head[u],head[u]=cnt;}
11 inline int read()
12 {
13     int T=0,F=1; char ch=getchar();
14     while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
15     while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
16     return F*T;
17 }
18 void tarjan(int u)
19 {
20     low[u]=dfn[u]=++deep; x[++top]=u; v[u]=1;
21     for(int i=head1[u];i;i=e[i].nxt)
22     {
23         if(!dfn[e[i].to]) tarjan(e[i].to),low[u]=min(low[u],low[e[i].to]);
24         else if(v[e[i].to]) low[u]=min(low[u],low[e[i].to]);
25     }
26     if(dfn[u]==low[u])
27     {
28         num[u]=++tot; v[u]=0;
29         while(x[top]!=u) v[x[top]]=0,num[x[top]]=tot,--top;
30         --top;
31     }
32 }
33 void tppx()
34 {
35     queue<int> q; cnt=0;
36     for(int i=1;i<=tot;++i) if(!rd[i]) x[++cnt]=i,q.push(i);
37     while(!q.empty())
38     {
39         int tmp=q.front(); q.pop();
40         for(int i=head2[tmp];i;i=f[i].nxt)
41         {
42             --rd[f[i].to];
43             if(!rd[f[i].to]) x[++cnt]=f[i].to,q.push(f[i].to);
44         }
45     }
46 }
47 int main()
48 {
49     n=read(); m=read();
50     for(int i=1;i<=n;++i) w1[i]=read();
51     for(re int i=1;i<=m;++i) t1=read(),t2=read(),add(t1,t2,e,head1);
52     for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
53     cnt=0;
54     for(int i=1;i<=n;++i)
55     {
56         w2[num[i]]+=w1[i];
57         for(int j=head1[i];j;j=e[j].nxt) if(num[i]!=num[e[j].to]) add(num[i],num[e[j].to],f,head2),++rd[num[e[j].to]];
58     }
59     memset(x,0,sizeof(x)); tppx();
60     for(int i=1;i<=n;++i)
61     {
62         t=x[i]; ans[t]=max(ans[t],w2[t]);
63         maxa=max(maxa,ans[t]);
64         for(int j=head2[t];j;j=f[j].nxt) ans[f[j].to]=max(ans[f[j].to],ans[t]+w2[f[j].to]);
65     }
66     printf("%d\n",maxa);
67     return 0;
68 }

?

? ??

轉載于:https://www.cnblogs.com/ljk123-de-bo-ke/p/10686498.html

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

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

相關文章

mysql多表聯合刪除

文件一&#xff1a;01.txt文件二&#xff1a;02.txt登錄mysql選擇數據庫表user結構表user_depart結構導入數據到表user導入數據到表user_depart聯合刪除查看刪除后user表的數據查看刪除后user_depart表的數據本文轉自 Lee_吉 51CTO博客&#xff0c;原文鏈接:http://blog.51cto.…

Jenkins 隨筆

window是 隨筆 修改端口 &#xff1a; <arguments>-Xrs -Xmx256m -Dhudson.lifecyclehudson.lifecycle.WindowsServiceLifecycle -jar "%BASE%\jenkins.war" --httpPort8181 --webroot"%BASE%\war"</arguments> 然后重啟服務&#xff08;服務…

centos 初學者_初學者:如何在Outlook 2013中創建和管理任務

centos 初學者If you’re one of those people who has a whiteboard or notepad with an ever-evolving to-do list, or your desk and monitors are adorned with Post-its reminding you of important events, then this the article for you. 如果您是擁有不斷發展的待辦事…

C語言基礎(五)

一、字符串相關函數 1.gets()(輸入字符串) 格式&#xff1a;gets(字符串)&#xff1b; (1)區別&#xff1a;gets(str)與scanf(“%s”,str) gets(str)允許輸入的字符串含有空格 scanf(“%s”,str)不允許含有空格 注意&#xff1a;由于以上無法知道字符串大小&#xff0c;很容易導…

新服務器安裝和配置zabbix的playbook

公司的金山區云服務器是由我負責的&#xff0c;每一次新購買了金山區的服務器都要把這些新服務器添加到zabbix監控里&#xff0c;于是我就編寫了一個ansible的playbook&#xff0c;這樣以后就可以在執行playbook的時候“帶薪拉屎”了。 ansible主機準備&#xff1a; 1&#xff…

15個變態的Google面試題以及答案

在當前經濟形勢不景氣的情況下&#xff0c;谷歌招聘新員工是一件令人振奮的事&#xff0c;特別是對那些在當前金融風暴中渴望找到安全港的年輕經理們和軟件開發商們來說是個好消息。   不過&#xff0c;也不要高興太早&#xff0c;谷歌在招聘新員工時&#xff0c;更加青睞名牌…

小程序禁用ios 左右滑動_如何在使用應用程序時禁用iOS控制中心

小程序禁用ios 左右滑動The Control Center has proven to be a thoughtful and welcome addition to iOS, but it can be annoying sometimes if you’re playing a game or using an app, and you accidentally open it. Here’s how you can disable it in such situations.…

repomd.xml錯誤14 not found

用Centos7最小化安裝了系統&#xff0c;想練練手&#xff0c;可以到換了“搜狐”的YUM源&#xff0c;系統總報錯更新錯誤說找不到repomd.xml。 然后就一直搜解決問題&#xff0c;能用到的都用到了&#xff0c;網上提到的都用到了。浪費了好幾個小時沒解決。正當無語的時候&…

淺談javascript遞歸(白話版)

遞歸 遞歸是一種解決問題的方法&#xff0c;通常我們可以理解成函數調用自身&#xff1b; 什么遞歸&#xff1f;遞歸怎么寫&#xff1f; 首先直接調用自身的方法和函數&#xff0c;他是一個遞歸&#xff0c;我們看代碼&#xff1a; 復制代碼 var recursiveFun function(params…

超鏈接禁用_如何在Microsoft Word中禁用超鏈接

超鏈接禁用When you type a web or email address in Word, you may notice that the program automatically formats it as a live hyperlink. This is a setting in Word’s AutoFormat feature that is on by default but can be easily turned off. 當您在Word中鍵入網站或…

ssh面試題總結

題目1&#xff1a;Hibernate工作原理及為什么要用&#xff1f; 原理&#xff1a; hibernate&#xff0c;通過對jdbc進行封裝&#xff0c;對 java類和 關系數據庫進行mapping&#xff0c;實現了對關系數據庫的面向對象方式的操作&#xff0c;改變了傳統的jdbc sql操作數據的方式…

SaltStack的salt-ssh使用及LAMP狀態設計部署

SaltStack的salt-ssh使用及LAMP狀態設計部署 1、salt-ssh的使用 官方文檔&#xff1a;https://docs.saltstack.com/en/2016.11/topics/ssh/index.html &#xff08;1&#xff09;安裝salt-ssh [rootlinux-node1 ~]# yum install -y salt-ssh&#xff08;2&#xff09;配置salt-…

程序員筆記(知識)管理的一點經驗

記筆記這件事&#xff0c;也許在很多人看來&#xff0c;再普通、簡單不過了——從小老師就教育我們要這么做。不同的人有不同的方式&#xff0c;我們最終的目的&#xff0c;還是希望不要停留在只是記錄這一層面上&#xff0c;而是將它們轉變為我們的知識。作為一個程序員&#…

xbox可以錄視頻聲音嗎_什么是Xbox Live Gold,它值得嗎?

xbox可以錄視頻聲音嗎If you have an Xbox One or Xbox 360, Microsoft’s Xbox Live Gold service is required to play multiplayer games online. A subscription costs $10 per month or $60 per year. Xbox Live Gold also includes additional benefits, like free games…

windows - mysql

Windows:(mysql)操作:0.下載安裝mysql www.mysql.org downloads community 5.7.21 下載5.6 Microsoft Windows 解壓到C: C:\mysql-5.6.39-winx64 C:\mysql-5.6.39-winx64\bin bin/mysql 客戶端 bin/mysqld 服務端 設置環境變量: …

顯示器選三星還是飛利浦_如何為飛利浦色相燈設置計時器

顯示器選三星還是飛利浦Maybe you want to turn off your Philips Hue lights after a certain amount of time has passed, or have them blink as a reminder. Whatever your needs, here’s how to set a timer for your Philips Hue lights to have them automatically tur…

PIE SDK與OpenCV結合說明文檔

1.功能簡介 OpenCV是基于BSD許可&#xff08;開源&#xff09;發行的跨平臺計算機視覺庫&#xff0c;可以運行在Linux、Windows、Android和Mac OS操作系統上。它輕量級而且高效——由一系列 C 函數和少量 C 類構成&#xff0c;同時提供了Python、Ruby、MATLAB等語言的接口&…

js的棧堆與淺拷貝、深拷貝的理解

一&#xff1a;什么是堆棧&#xff1f; 我們都知道&#xff1a;在計算機領域中&#xff0c;堆棧是兩種數據結構&#xff0c;它們只能在一端(稱為棧頂(top))對數據項進行插入和刪除。 堆&#xff1a;隊列優先,先進先出&#xff1b;由操作系統自動分配釋放 &#xff0c;存放函數的…

python面向對象基礎語言進階

在此感謝前輩們的指導&#xff1a;http://python.jobbole.com/80955/ https://www.cnblogs.com/wupeiqi/p/4766801.htmlhttps://www.cnblogs.com/paomaliuju/p/5122761.html https://www.cnblogs.com/goser/articles/7097728.html http://www.cnblogs.com/alex3714/articles/52…

ea 備份碼是什么_EA的原始訪問是什么,值得嗎?

ea 備份碼是什么EA’s Origin Access gives you access to more than 70 games, discounts, and new EA games before they’re released for a monthly (or yearly) subscription fee. But is it really worth it? EA的Origin Access可讓您訪問70多種游戲&#xff0c;打折游戲…