ACM模板 圖論
@(ACM模板)[圖論]
圖論知識點要求
必須會:
- 次短路&&路徑數
- 生成樹(看裡面的過程)
- 最大流(主要是模板)
- 割(論文:最小割模型在資訊競賽裡的應用)
- 二分圖
- 樹的分治,(點分治如重心分解,邊分治如樹鏈剖分)
瞭解,會套模板即可:
- K短路
- 度限制MST~end
- ZKW陣列模擬
- 一般圖匹配(NP,套模板)
- 各種迴路
- 瞭解經典問題
General
- 注意下標是0-indexed的還是1-indexed的
- 看好是否有重邊、自環
- 多組資料,vector要clear
- 在無向圖中,存邊的陣列的大小要開邊數的兩倍
- unidirectional 和 one-way都是單向邊
建圖
使用vector
略
鏈式前向星
- 設圖中n個點,m條邊。在稀疏圖(
m≪n )中表示圖,可以用鄰接表。每個結點i有一個連結串列,儲存從i出發的所有邊。 - 方法:用陣列模擬連結串列:
- 每條邊編號
- first[u]儲存結點u的第一條邊的編號
- next[e]表示編號為e的邊的下一條邊的編號
- 注意每次插到連結串列的首部而非尾部,避免遍歷
- 程式碼實現
typedef long long LL;
const int maxn = ?;
const int maxm = ?;
int n, m;
int head[maxn], next[maxm];
struct Edge
{
int to;
int dis;//LL
Edge(int to = 0, int dis = 0):to(to),dis(dis) {}
}edges[maxm];//無向圖size為2*maxm
void build_graph()
{
cin >> n >> m;
memset(head, 0xff, sizeof head);
int u, v, w;
for(int i = 0; i < m; ++i)
{
scanf("%d%d%d", &u, &v, &w);
edges[i] = Edge(u, v, w);
//無向圖要加兩條
next[i] = head[u];
head[u] = i;
}
}
遍歷u的所有邊
for(int e = first[u]; ~e; e = next[e])
{
//...
}
最短路
1. Dijkstra演算法
思想&步驟:
1. 初始化:d[s] = 0, 其他d為INF, 確定點集裡只有s
2. 從未被確定的點的集合裡找d最小的,加入確定的點集,並更新其他d
3. 重複2直到所有點都確定
注意:
- 不能處理負權。原因:Dijkstra貪心的找未確定點集裡d最小的,若有負權可能之後找到d更小的。
- 此為使用佇列優化的版本,複雜度
- 基礎版執行n次,每次遍歷所有點,複雜度
基礎版即使在
程式碼
注意:
- 若最短路是long long 的,下面的程式碼需要在相應註釋的地方更改
- 若需記錄路徑,需要啟用pa[]陣列
- 注意點的下標是否從0開始
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5+5;//頂點數
const int maxm = 1e5+5;//邊數
struct Dijstra//d[t] < inf代表有解
{
const int inf = 0x3f3f3f3f;
//const LL inf = 0x3f3f3f3f3f3f3f3f;
int n, m;
bitset<maxn> done;
int d[maxn];//LL
int head[maxn];
//int par[maxn];//記錄路徑
struct Edge
{
int to, nxt;
int dis;//LL
}e[maxm];
struct Node
{
int u;//結點編號
int dis;//LL
bool operator<(const Node &rhs) const
{
return dis > rhs.dis;
}
};
void init(int nn)
{
n = nn;
m = 0;
memset(head, 0xff, sizeof head);
}
void addEdge(int from, int to, int dis)//LL dis
{
e[m].to = to;
e[m].dis = dis;
e[m].nxt = head[from];
head[from] = m++;
}
void finda(int s)
{
priority_queue<Node> q;
for(int i = 0; i < n; ++i) d[i] = inf;//0~n-1,注意下標從哪裡開始
d[s] = 0;
done.reset();
q.push((Node){s, 0});
while(!q.empty())
{
int u = q.top().u;
q.pop();
if(done[u] == true) continue;
done[u] = true;
for(int i = head[u]; ~i; i = e[i].nxt)
{
int v = e[i].to;
int dis = e[i].dis;//LL
if(d[v] > d[u] + dis)
{
d[v] = d[u] + dis;
q.push((Node){v, d[v]});
}
}
}
}
};
2. Bellman-Ford演算法
思想&步驟
1. 初始化 所有頂點 d[i] = INF, 令d[s] = 0
2. 列舉每條邊進行鬆弛,不能鬆弛時演算法結束
3. 重複2,使2進行n-1次
memset(d, 0x3f, sizeof d);
d[s] = 0;
for(int times = 1; times < n; ++times)
{
for(int i = 0; i < m; ++i)
{
int x = u[i], y = v[i];
if(d[y] < d[x] + w[i]) d[y] = d[x] + w[i];
}
}
3 .SPFA演算法
思想&步驟:
“鬆弛操作的連鎖反應”
用queue存可用來鬆弛的點,每次用隊首點進行鬆弛,然後將鬆弛到的&&不在queue中的點加入queue。
注意:
- 此為Bellman-Ford演算法的佇列優化版本
- 可以判斷負環。因為任意一條最短路,所經過的點不會超過n,那麼任何一點不可能超過(n-1)次被鬆弛。
- 最壞情況複雜度
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxm = 1e5 + 5;
const int maxn = 1e5 + 5;
struct SPFA
{
const int inf = 0x3f3f3f3f;
//const LL inf = 0x3f3f3f3f3f3f3f3f;
bool vis[maxn];
int c[maxn], head[maxn];//c為入隊次數
int d[maxn];//LL
int n, m;
struct Edge
{
int to, nxt;
int dis;//LL
}e[maxm];
void init(int nn)
{
n = nn;
m = 0;
memset(head, 0xff, sizeof head);
}
void addEdge(int from, int to, int dis)//LL dis
{
e[m].to = to;
e[m].dis = dis;
e[m].nxt = head[from];
head[from] = m++;
}
queue<int> q;
bool finda(int s)//若存在負環返回true
{
memset(d, 0x3f, sizeof d);
d[s] = 0;
memset(vis, 0, sizeof vis);
memset(c, 0, sizeof c);
while(!q.empty()) q.pop();
q.push(s);
vis[s] = true;
c[s] = 1;
while(!q.empty())
{
int x = q.front();
q.pop();
vis[x] = false;
for(int i = head[x]; ~i; i = e[i].nxt)
{
int y = e[i].to;
int dis = e[i].dis;
if(d[y] > d[x] + dis)
{
d[y] = d[x] + dis;
if(!vis[y])
{
vis[y] = true;
++c[y];
q.push(y);
if(c[y] > n) return true;
}
}
}
}
return false;
}
};
4. Floyd演算法
for(int k = 0; k < n; ++k)
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j)
if(d[i][j] < INF && d[k][j] < INF)
d[i][j] <?= d[i][k]+d[k][j];
若距離陣列為bool,代表是否聯通,則得到的結果成為有向圖的傳遞閉包
5. 差分約束
- 若全部不等式均為
xi−xj≤aij 的形式(注意有等號),求xs−xt 的最大值。可以建圖求最短路。 - 對於
xi−xj≤aij ,建立xj→xi 的有向邊,權值為aij - 解的存在性:
- 存在最短路:
xs−xt 存在最大值 - 存在負環:
xs−xt 無窮小 - 圖中不可達,無最短路:
xs−xt 無窮大
- 存在最短路:
- 若全部不等式均為
xi−xj≥aij 的形式,求xs−xt 的最小值。可以改為在建好的圖中求最長路。 - 若不等式中既含有
≤ 又含有≥ ,可以通過變號統一處理成≤ 或≥ ,處理成≤ 還是≥ 取決於最後是求最大值還是最小值。 - 若含有不帶等號的不等式
xi−xj<aij ,且涉及到的都是整數,可以等價變形為xi−xj≤aij+1 - 最終的每個
di 值為xi 的可行解。若{x0,x1,⋯xn−1,xn} 是一組可行解,則{x0+y,x1+y,⋯xn−1+y,xn+y} 也是。
6. 最長路
- 方法一:將原圖中的每條邊權取相反數,再用Bellman-Ford或SPFA求解最短路。注意不能使用Dijkstra演算法,因為其無法處理負權。
- 方法二:將再用Bellman-Ford或SPFA中的鬆弛條件反向,直接求解最長路。
- 再次注意不要用Dijkstra演算法
- 存在正環時,不再計算d[t],此時要注意圖的聯通性,即從該正環是否能走到終點。(Floyd)
例題:poj1932
7. 次短路
對Dijkstra演算法進行修改。增加一個用於記錄次短路的陣列d2。
在進行鬆弛操作時
- 若可更新最短路,則更新最短路,原最短路變為次短路
- 若可更新次短路,則更新次短路
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 5;//頂點數
const int maxm = 1e5 + 5;//邊數
const int inf = 0x3f3f3f3f;
//const LL inf = 0x3f3f3f3f3f3f3f3f;
struct Dijstra//d2[t] < inf代表有解
{
int n, m;
int d[maxn], d2[maxn];//LL,d記錄最短路,d2記錄次短路
int head[maxn];
//int par[maxn];//記錄路徑
struct Edge
{
int to, nxt;
int dis;//LL
}e[maxm];
struct Node
{
int u;//結點編號
int dis;//LL
bool operator<(const Node &rhs) const
{
return dis > rhs.dis;
}
};
void init(int nn)
{
n = nn;
m = 0;
memset(head, 0xff, sizeof head);
}
void addEdge(int from, int to, int dis)//LL dis
{
e[m].to = to;
e[m].dis = dis;
e[m].nxt = head[from];
head[from] = m++;
}
void finda(int s)
{
priority_queue<Node> q;
for(
相關推薦
ACM模板 圖論
@(ACM模板)[圖論]
圖論知識點要求
必須會:
- 次短路&&路徑數
- 生成樹(看裡面的過程)
- 最大流(主要是模板)
- 割(論文:最小割模型在資訊競賽裡的應用)
- 二分圖
- 樹的分治,(點分治如重心分解,
ACM之圖論基本演算法詳解
圖論基本演算法
DFS,BFS
兩個生成樹prim + Kruskal
4個最短路徑Dijkstra+Floyd+Bellman-Ford+SPFA
DFS&BFS
DFS——遍歷所有解
模板:
void DFS( Point
洛谷P3385 【模板】負環 DFS-SPFA 判負環 圖論
string inf scan space can 清空 span %d pre 洛谷P3385 【模板】負環
圖論
今天get了 一個 DFS-SPFA 判負環的方法
一般的 BFS-SPFA 判負環 一般就是 不停地做,如果某點第 n+1次加入隊列中,那麽說明這個圖存在
圖論算法-Tarjan模板 【縮點;割頂;雙連通分量】
else if false -m 例如 als for 算法思路 連通 tarjan 圖論算法-Tarjan模板 【縮點;割頂;雙連通分量】
為小夥伴們總結的Tarjan三大算法
Tarjan縮點(求強連通分量)
int n;
int low[100010],dfn[1
圖論題目模板,和並查集:以後的圖論題目就靠他了
fat union 一次 情況 返回 end empty 是我 min
‘‘‘
並查集:
1.用於查如何A,B是否在一個集合中.
2.每一個集合設立一個頭結點.其他都連向他
3.集合合並就是把小的集合掛到大的集合下面即可
4.優化.查詢到一個a在b這個頭結點下面,那麽直
noip提高組圖論模板
//拓撲排序
void Top(){
for(i=1;i<=n;++i)
if(!du[i]) q.push(i);
while(!q.empty()){
int u=q.front();q.pop();
ans[++num]=u;
for(int i=head[u];i;
NOIP複賽複習(五)程式對拍與圖論模板
程式對拍
所謂“對拍”,顧名思義,就是讓兩者相互比對。所謂“兩者”,一是你要測試的程式,二是一個答案在該程式在一定範圍(時間/空間)內結果必定正確的程式(一般是用暴力求解的程式)。對拍一般需要造資料程式(data.exe),保證正確性的暴力對拍程式(test.exe)與測試程式(以moo.e
【模板】圖論
線段樹優化 cpp 算法 圖論 n) while uil ont 堆優化 基礎圖論
鏈式前向星
帶權值
int head[400001],ver[2000001],nxt[2000001],val[2000001],tot=0;
void add(int x,int y,i
幹貨系列——模板 之 圖論1
class con ·· spfa算法 幹貨 jks true 鏈式 dijk 圖論常用模板:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
圖的建立
複習1-圖論模板
1.最短路
圖全為正權使用Dijkstra,有負權用SPFA,Bellman-Ford稍加了解即可
void spfa(){
queue<int> q;
for(int i = 1;i <= n;i++) d[i] = 0x7fffffff;
圖論演算法模板
Under the bridge downtown
Forgot about my love
Under the bridge downtown
I gave my life away
Luogu P4779【模板】單源最短路徑(標準版)
//時間複雜度O((n+m)log
圖論 模板(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),
分別表示這個畫中有多
模板庫(三) - 圖論演算法模板
寫在前面
“模板庫”這一系列文章用來複習
O
I
OI
圖論-環-洛谷P3385【模板】負環
這道題有毒啊。。輸出的不是“NO”是“N0”,不是“YES”而是“YE5”。被坑了一晚上。
另外,spfa-dfs竟然被卡死了,只能過9個點。換成三行就寫完的Bellmam-Ford就AC了
SPFA-
圖論:HDU-4009 Transfer water (最小樹形圖模板)
XiaoA lives in a village. Last year flood rained the village. So they decide to move the whole village to the mountain nearby this year. T
【圖論】單源點最短路模板(有向圖)Dijkstra
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#in
NOIP模板複習——圖論
由於圖論中有些演算法的程式碼比較長,就只貼核心程式碼
最短路
floyd
void floyd()
{
int i,j,k;
for(k=1;k<=n;++k)
for(i=1;i<=n;++i)
for(j=1;j<=n;++j
ACM圖論__有向圖的強連通分支演算法
求有向圖的強連通分支,主要有兩種演算法tarjan演算法和kosaraju演算法,這裡介紹tarjan演算法先來看幾個定義:(1)連通:兩個點可以相互到達(2)強連通(strongly connected): 在一個有向圖G裡,設兩個點 a b 發現,由a有一條路可以走到b,