圖論 模板(2)
Tarjan演算法
割點(割頂)
#include<cstdio>
#include<cstring>
#include<algorithm>
#define _ 200010
using namespace std;
struct node{int x,y,next;} a[_];
int n,m,len=0,id=0,ans=0;
int last[_],low[_],dfn[_];
/*dfn[i]表示點i被訪問的時間戳
low[i]表示點i及i的子樹中所有結點能到達的結點中dfn最小的結點的時間戳*/
bool bz[_];//是不是割點
void ins (int x,int y)
{
a[++len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len;
}
void dfs(int x,int root)
//x表示當前訪問到第x個點,root表示以root為根節點的子樹的根
{
int tot=0;//入度(及子樹數)
low[x]=dfn[x]=++id;
//記錄時間戳
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(!dfn[y])
{
dfs(y,root);
low[x]=min(low[x],low[y]);
//更新當前節點的low值
if(low[y]>=dfn[x]&&x!=root) bz[x]=true;
/*非根且子樹能達到的dfn最小的結點的時間>=自己的時間時,
說明它的子樹中最早能訪問到的結點都比它後訪問,此時只要不為根就一定是割點*/
if(x==root) tot++;
//更新入度
}
low[x]=min(low[x],dfn[y]);
//把點x及x的子樹可以達到的dfn的最小結點更新
}
if(x==root&&tot>=2) bz[root]=true;
/*如果一個點為根且入度>=2(即有兩個子樹),則一定為割點,
因為一棵樹的根一刪,那麼它的子樹一定不連通了*/
}
int main()
{
int x,y;
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d",&x,&y);
ins(x,y);
ins(y,x);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) dfs(i,i);
for(int i=1;i<=n;i++)
if(bz[i]) ans++;
printf("%d\n",ans);//割點的總數
for(int i=1;i<=n;i++)
if(bz[i]) printf("%d ",i);//輸出割點
return 0;
}
割邊(橋)
#include<bits/stdc++.h>
#define _ 110000
using namespace std;
struct rec
{
int y, next;
}edge[_],cut[_];
int n,m,id=0,len=0;
int dfn[_], low[_];
int head[_], bz[_], link[_];
void Add(rec *edge,int x,int y,int *head)
{
edge[++len].y = y,edge[len].next = head[x],head[x] = len;
}
void tarjan(int x)
{
dfn[x]=low[x]=++id;
for (int i =head[x]; i; i =edge[i].next)
{
int y = edge[i].y;
if (bz[x] == y) continue;
if (!dfn[y])
{
bz[y] = x;//是y的爸爸為x!!
tarjan(y);
low[x] = min(low[x], low[y]);
if (low[y] > dfn[x]) Add(cut, x, y, link);
}//此處無=號!!
low[x] = min(low[x], dfn[y]);
}
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; ++i)
{
int x, y;
cin >> x >> y;
Add(edge,x,y,head);
Add(edge,y,x,head);
}
for (int i = 1; i <= n; ++i)
if (!dfn[i]) tarjan(i);
for (int x = 1; x <= n; ++x)
for (int i = link[x]; i; i = cut[i].next)
printf("%d %d\n",x,cut[i].y);
}
有向圖的強連通分量
//強連通分量
#include<bits/stdc++.h>
#define _ 100010
#define $ 1000010
using namespace std;
inline int read()
{
int f=1,num=0;
char ch=getchar();
while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
while (ch>='0'&&ch<='9') num=(num<<1)+(num<<3)+ch-'0', ch=getchar();
return num*f;
}
int ver[$],Next[$],link[_],len=0;
void add(int x,int y)
{
ver[++len]=y,Next[len]=link[x],link[x]=len;
}
int dfn[_],low[_],id=0,belong[_];
int Stack[_],top=0,tot=0;
int instack[_];
vector<int>scc[_];
void tarjan(int x)
{
dfn[x]=low[x]=++id;
instack[x]=1;
Stack[++top]=x;
for(int i=link[x];i;i=Next[i])
{
int y=ver[i];
if(!dfn[y])
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(instack[y])
low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x])
{
int k;
++tot;
do
{
k=Stack[top--], instack[k]=0;
belong[k]=tot, scc[tot].push_back(k);
}while (k!=x);
}
}
int main()
{
int n=read(),m=read();
for(int i=1;i<=m;++i)
{
int x=read(),y=read();
add(x,y);
}
for(int i=1;i<=n;++i)
if(!dfn[i]) tarjan(i);
for (int i=1;i<=tot;++i)
{
printf("SCC #%d:",i);
for (int j=0;j<scc[i].size();++j)
printf(" %d",scc[i][j]);
puts(" ");
}
return 0;
}
附上一個求最大強連通分量的例題
洛谷 p1726
描述 Description
在幻想鄉,上白澤慧音是以知識淵博聞名的老師。春雪異變導致人間之裡的很多道路都被大雪堵塞,使有的學生不能順利地到達慧音所在的村莊。因此慧音決定換一個能夠聚集最多人數的村莊作為新的教學地點。人間之裡由N個村莊(編號為1…N)和M條道路組成,道路分為兩種一種為單向通行的,一種為雙向通行的,分別用1和2來標記。如果存在由村莊A到達村莊B的通路,那麼我們認為可以從村莊A到達村莊B,記為(A,B)。當(A,B)和(B,A)同時滿足時,我們認為A,B是絕對連通的,記為<A,B>。絕對連通區域是指一個村莊的集合,在這個集合中任意兩個村莊X,Y都滿足<X,Y>。現在你的任務是,找出最大的絕對連通區域,並將這個絕對連通區域的村莊按編號依次輸出。若存在兩個最大的,輸出字典序最小的,比如當存在1,3,4和2,5,6這兩個最大連通區域時,輸出的是1,3,4。
輸入格式 Input Format
第1行:兩個正整數N,M
第2…M+1行:每行三個正整數a,b,t, t = 1表示存在從村莊a到b的單向道路,t = 2表示村莊a,b之間存在雙向通行的道路。保證每條道路只出現一次。
輸出格式 Output Format
第1行: 1個整數,表示最大的絕對連通區域包含的村莊個數。
第2行:若干個整數,依次輸出最大的絕對連通區域所包含的村莊編號。
樣例輸入 Sample Input
5 5
1 2 1
1 3 2
2 4 2
5 1 2
3 5 1
樣例輸出 Sample Output
3
1 3 5
時間限制 Time Limitation
1s
註釋 Hint
對於60%的資料:N <= 200且M <= 10,000
對於100%的資料:N <= 5,000且M <= 50,000
#include<bits/stdc++.h>
#define _ 100010
using namespace std;
inline int read()
{
int f=1,num=0;
char ch=getchar();
while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
while (ch>='0'&&ch<='9') num=(num<<1)+(num<<3)+ch-'0', ch=getchar();
return num*f;
}
int head[_],ver[_],Next[_],len;
void add(int x,int y)
{
ver[++len]=y,Next[len]=head[x],head[x]=len;
}
int dfn[_],low[_],id=0;
int belong[_],siz[_];
int Stack[_],top=0,tot=0;
int instack[_];
void tarjan(int x)
{
low[x]=dfn[x]=++id;
instack[x]=1;
Stack[++top]=x;
for(int i=head[x];i;i=Next[i])
{
int y=ver[i];
if(!dfn[y])
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(instack[y])
low[x]=min(low[x],dfn[y]);
}
int k;
if(low[x]==dfn[x])
{
++tot;
do
{
k=Stack[top];
siz[tot]++;
--top;
instack[k]=0;
belong[k]=tot;
} while (k!=x);
}
}
int maxn=-1;
int main()
{
int n=read(),m=read();
for(int i=1;i<=m;i++)
{
int x=read(),y=read(),z=read();
add(x,y);
if(z==2) add(y,x);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
int dcc;
for(int i=1;i<=n;i++)
if(siz[belong[i]]>maxn)
maxn=siz[belong[i]],dcc=i;
printf("%d\n",maxn);
for(int i=1;i<=n;i++)
if(belong[i]==belong[dcc]) printf("%d ",i);
return 0;
}
無向圖的雙連通分量
E-DCC (邊-雙連通分量) 模板
/*
*邊雙連通分量(e-DCC)的求法
*/
#include<bits/stdc++.h>
#define _ 100010
using namespace std;
int head[_],ver[_*2],Next[_*2];
int dfn[_],low[_],n,m,tot,id;
bool bridge[_*2];
void add(int x,int y)
{
ver[++tot]=y,Next[tot]=head[x],head[x]=tot;
}
void tarjan(int x,int inEdge)
{
dfn[x]=low[x]=++id;
for (int i=head[x];i;i=Next[i])
{
int y=ver[i];
if (!dfn[y])
{
tarjan
相關推薦
圖論 模板(2)
Tarjan演算法
割點(割頂)
#include<cstdio>
#include<cstring>
#include<algorithm>
#define _ 200010
using namespace std;
struct node{
圖論 模板(1)
最短路(ShortextPath)
Dijkstra
#include<bits/stdc++.h>
using namespace std;
/*Dijkstra演算法*/
int a[3010][3010],d[3010],n,m;
bool v[3010];
圖論 模板(3)
一筆畫問題(尤拉路)
DFS版
/*1.一筆畫問題
*規定 所有的邊都只能畫一次,不能重複畫
*輸入
第一行只有一個正整數N(N<=10)表示測試資料的組數.
每組測試資料的第一行有兩個正整數P,Q(P<=1000,Q<=2000),
分別表示這個畫中有多
圖論講解(1)——圖基礎
同學 根據 tdi sin images 鄰接表 c++ algo ack 前面一直在嗶嗶數論,是不是感覺很煩的慌了??
╮(╯▽╰)╭唉,你不煩得慌我都煩得慌了!
既然這樣,那我們就改個話題,今天我們就講講圖論。
有的同學就要問圖又是個什麽鬼?
難道是這個嗎?
第21課 可變參數模板(2)_展開參數包
delet pre 控制 seq src 構造 pro head del 1. 可變參數模板函數
(1)遞歸函數方式展開參數包
①一般需要提供前向聲明、一個參數包的展開函數和一個遞歸終止函數。
②前向聲明有時可省略,遞歸終止函數可以是0個或n個參數
(2)逗號表達式
【AI基礎】python:openCV——圖像處理(2)
getTrackbarPos圖像處理練習
制作一個滑動條調色板,使用函數cv2.getTrackbarPos();cv2.creatTrackbar()
import cv2
import numpy as np
def nothing(x):
pass
img = np.zeros((300,5
並不對勁的圖論專題(三):SPFA算法的優化
a算法 bubuko 等於 dfs size iomanip 最小 bre else if 1.bzoj1489->
這是個新套路。
我們希望找到最小的x,那麽可以二分x,然後判斷是否存在圈的邊權的平均值小於等於x。
設圈的邊權依次為w1,w2,w3,…,wk,平均值
python圖像處理(2)圖像水印和PIL模式轉化
tex 我們 參考 height rom 設置 分享 show pen 模式轉化:
PIL模式轉化:將圖片轉化成其他模式
1 # 我們將image圖像轉化為灰度圖像(python)
2 from PIL import Image
3 img = Image.open
Django基於第一個項目導入模板(2)
分享 template bubuko 項目 服務器 http brush 新建文件夾 temp 1.在模塊blog下新建文件夾templates,在templates下新建index.html文件
//index.html代碼如下:
<html>
<
PAT 備考第一天——圖論演算法(一)
大綱:
必考考點: 1.圖的定義和相關術語 2.圖的儲存(鄰接矩陣和鄰接表) 3.圖的遍歷(DFS和BFD) 4.最短路徑演算法 5.拓撲排序
非重點考點: 1.關鍵路徑 2.最短路徑中的Bellman-Ford和SPFA
甲級考綱以外的考點: 最小生成樹演算法
一、圖的
圖論:(半)尤拉圖與(半)哈密頓圖
圖論:尤拉圖與哈密頓圖
圖論最基本的要素就是點和邊,尤拉圖和哈密頓圖是分別關於點和邊的兩種特殊圖的形式。
尤拉圖側重於經過所有的點,哈密頓圖側重於經過所有的邊。
尤拉圖
尤拉路徑:一條路徑在圖G中恰好經過每條邊一次。尤拉通路:通過圖中所有邊的簡單路(其實就是每條邊經過
圖論演算法(六)-- 二分圖的最大分配問題(JAVA)
二分圖:又稱二部圖,如果一個圖的所有頂點可以被分為X和Y兩個集合,並且所有邊的兩個頂點恰好一個屬於一個集合X,另一個屬於集合Y,即每個集合內的頂點沒有邊相連,那麼這個圖就是二分圖。
二分圖的最大分配問
圖論演算法(一)
圖的基本概念及表示
圖的基本概念
圖(graph)可視為一有序二元組G = (V,E), 其中V = {v1,v2,……,vn}為頂點集,V中的元素稱為頂點(vertex),E = {e1,e2,……,en}稱為邊集,E中的元素成為邊(edge)。E
圖論演算法(3)--- A*演算法求k短路
在一個有向圖中,如何求出前k短路,比較高效的演算法我們自然想到了A*演算法,這裡賦上程式碼,所有講解將放在程式碼註釋中:
如對A*有基礎性知識的疑問,請參考此文:A*搜尋演算法
import java.io.File;
import java.io.IOException;
圖論演算法(4) --- TSP旅行商問題 求最短迴路(acm)
對於TSP旅行商問題,我們做的最多的也就是求最短迴路了,那麼對於一個數據量適中的圖來說,一般的dfs方法即可求解,在這裡,我應用dfs的思想來實現此問題,而關鍵之處在於對矩陣的改進,這樣的操作可以使得應用搜索思想求TSP問題時,效率有顯著的提高。對於矩陣的改進,我們對矩陣的
圖論演算法(一)--最短路徑的DFS/BFS解法(JAVA )
最短路徑–城市路徑問題:
問題描述:求從1號城市到5號城市的最短路徑長度
Input:
5 8
1 2 2
1 5 10
2 3 3
2 5 7
3 1 4
3 4 4
python科學計算學習二:matplotlib繪圖,圖標註釋(2)
圖標註釋對於搞研究的人來說是很重要的,一般的paper裡面也都會有。所以是很有必要要學習的。
下面通過一個例子來說明python是怎麼做的。
1 import matplotlib.pyplot as plt
2 import numpy as n
圖論演算法(五)--求解割點、割邊(JAVA)
割點:對於一個連通圖來說,如果刪除某個點之後圖不再連通,這個點就稱為割點
割點演算法
時間複雜度:O(N+M)
但是下面給出的演算法時間複雜度為O(N^2),這是因為下面的儲存結構都是鄰接矩陣,這
PAT 備考——圖論演算法(二)最短路徑
最短路徑演算法是PAT甲級考試常考演算法,具體說來,最短路徑包括Dijkstra演算法、Floyd演算法,其餘的Bellman-Ford和SPFA基本不會考(參《演算法筆記》胡凡,曾磊著)
目錄
一、最短路徑基本概念與問題分類
1.基本概念
2.問題分類
二、D
NOIP複賽複習(五)程式對拍與圖論模板
程式對拍
所謂“對拍”,顧名思義,就是讓兩者相互比對。所謂“兩者”,一是你要測試的程式,二是一個答案在該程式在一定範圍(時間/空間)內結果必定正確的程式(一般是用暴力求解的程式)。對拍一般需要造資料程式(data.exe),保證正確性的暴力對拍程式(test.exe)與測試程式(以moo.e