一、最短路径问题
- 多源最短路径
Floyd:
void Floyd(int *d)
{
for(int k = 1; k <= n; ++ k)
for(int i = 1; i <= n; ++ i)
for(int j = 1; j <= n; ++ j)
{
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
return;
}
请记住此五行代码。
一般而言,可以用它判断图两点间的联通情况,称之为传递闭包,此时,仅需将转移的那一行改为:\(d[i][j]|=d[i][k]&d[k][j];\)
- 最小环问题(好好看看啊)
- 单源最短路径
以下示均使用邻接表。
Dijkstra:
void Dijkstra(int S)
{
priority_queue Q;
while(!Q.empty()) Q.pop();
memset(dis, 0x7f, sizeof(dis);
memset(vis, false, sizeof(vis));
Q.push(make_pair(0, S));
dis[S] = 0;
while(!Q.empty())
{
int u = Q.top().second;Q.pop();
if(vis[u]) continue;
vis[u] = true;
for(int i = 0; i < G[u].size(); ++ i)
{
int v = G[u][i];
if(dis[v] > dis[u] + W[u][i])
{
dis[v] = dis[u] + W[u][i];
Q.push(make_pair(-dis[v], v));
}
}
}
return;
}
spfa:
void SPFA(int S)
{
queue Q;
while(!Q.empty()) Q.pop();
memset(inq, false, sizeof(inq));
memset(dis, 0x7f, sizeof(dis));
Q.push(S);
inq[S] = true;
dis[S] = 0;
while(!Q.empty())
{
int u = Q.front();
Q.pop();
inq[u] = false;
for(int i = 0; i < G[u].size(); ++ i)
{
int v = G[u][i], w = W[u][i];
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
if(!inq[v])
{
inq[v] = 1;
Q.push(v);
}
}
}
}
return;
}
- 若要求得从源点到终点所有路径,能够经过的边权最小的权值时,应将\(dis[v] = dis[u] + w\)改为\(dis[v] = min(w, dis[u])\),而求最大值的时候,在Dijkstra还需要把堆写成大根堆;
- 当判断与源点相连是否存在负环的情况时,应当使用SPFA,在进行松弛操作的基础上加上一句话:\(cnt[v] = cnt[u] + 1\),其中\(cnt[i]\)指的是源点到节点i最短路径边的条数,则若\(cnt[v] ≥ n\),那么就判定为负环;
- 通常情况下,如果求每个节点到源点的最短路时,须要考虑建反图,跑一遍最短路即可;若记录最短路的条数时,应当更新(或松弛)的时候累加;
- 通常情况下,最短路更可能结合拓扑排序,请留意!
二、并查集
既能合并,又能查询的图论神器。
两种方法中,在图论中首选启发式合并。
//查询
int get(int x)
{
if(fa[x] == x) return x;
return get(fa[x]);
}
//合并
void merge(int x, int y)
{
if(dep[x] < dep[y]) swap(x, y);
int v = get(y);
fa[v] = x;
dep[x] += dep[y];
return;
}
主要用于存在多个联通块的情况。
此结构非常精巧,一定格外留意。
三、拓扑排序
不得不说,如果学图论时没有熟练掌握该操作,将是非常的遗憾。
代码如下:
void topsort() {
while(!Q.empty())
{
Q.pop();
}
for(int i = 1; i <= n; ++i) {
if(deg[i] == 0) {
Q.push(i);
}
}
while(!Q.empty()){
int x = Q.front();a.push_back(x);
Q.pop();
for(int i = 0; i < G[x].size(); ++ i){
int y = G[x][i];
--deg[y];
if(deg[y] == 0){
Q.push(y);
}
}
}
return;
}
拓扑排序用于判环、找结点的拓扑序等等。