點:就是點
邊:連接兩個點
無向邊:沒有方向性的邊
有向邊:有方向性的邊
權重:給邊或點加上一個數值,例如距離
從一個點\(v_0\)經過一些邊\((v_0, v_1), (v_1, v_2) ... (v_{k - 1}, v_k)\)到達另一個點\(v_k\)
的序列稱為路徑
可表示成經過的點的序列\((v_0, v_1, ... v_k)\)
路徑上沒有經過重複的點
就最短,可以是路徑上的邊權總和
一條路徑的起點和終點相同稱為環
就是可以走一圈回到原點
無向邊組成的圖
任意兩點之間都有路徑存在
就是可以從任意點走到其他所有點
圖中一些點,互相都有路徑存在,且不能被包含在其他連通塊內
就是其他的點都跟這些點不連通
有向邊組成的圖
沒有環的有向圖
點的數量是\(n\),編號為\(0\)~\(n-1\)
開一個\(n\times n\)的二維陣列A
如果A[i][j]=1,代表有一條邊從點i連接到點j
當邊的數量很少時,鄰接矩陣很多空間會浪費掉
鄰接串列只儲存有邊的資料
可用vector實作
走過所有的點
像人走路一樣
,選一條路一直走,走到不能再走之後退回來繼續找路
遞迴
vector<int> edge[100005];
bool visit[100005];
void dfs(int x) {
visit[x] = 1;
for (int i = 0; i < edge[x].size(); i++) {
if (!visit[edge[x][i]]) {
dfs(edge[x][i]);
}
}
}C++11小技巧
for(auto i:edge[x]){
if(visit[i]){
dfs(i);
}
}像是倒水
每次會先遍歷完所有經過一條邊可以到的點,接這遍歷兩條邊,以此類推
queue
把第一個拿出來,看有哪些點跟他連接且還沒被看過,把他們丟到queue後面
vector<int> edge[100005];
bool visit[100005];
void bfs(int x) {
queue<int> q;
q.push(x);
visit[x] = 1;
while (!q.empty()) {
int now = q.front();
q.pop();
for (auto i : edge[x]) {
if (!visit[i]) {
q.push(i);
visit[i] = 1;
}
}
}
}試著用dfs和bfs寫寫看
練習題:
zerojudge b517
有根樹有一個最頂端的根
有根樹上的問題比無根樹上簡單很多
最上面的點
最上面的點
一個點上面那一層的點,除了根節點外的點都只有一個父節點
最上面的點
一個點上面那一層的點,除了根節點外的點都只有一個父節點
一個點下面一層的點,可以有多個
最上面的點
一個點上面那一層的點,除了根節點外的點都只有一個父節點
一個點下面一層的點,可以有多個
沒有子節點的點
一個點的父節點和父節點的父節點....
也可以說是一個點到根節點路徑上的所有點
練習題:
tcirc judge d102
directed acyclic graph
有向無環圖
有n個工作,每個工作可能有一個或多個前置工作,問是否可以完成所有工作?
對於a工作,如果前置工作有b,
就連一條邊從b指向a
必須是DAG才有解
怎麼輸出解?
每次把沒有被指向的點拔掉
拔到沒有點為止
拔掉的順序就是一種答案
同時可以進行多個工作
求做完所有工作的最短時間
tcirc d099