寒假集训,今天是第七天,图论有关部分。
基础图论
图G是一个有序二元组(V,E),其中V称为点集(Vertices Set),E称为边集(Edges set),E与V不相交。它们亦可写成V(G)和E(G)。其中,点集的元素被称为顶点(Vertex),边集的元素被称为边(edge)

一些定义
有向/无向图 :边具有/不具有方向
完全图:每一对不同顶点恰有一条边相连的无向图
路径:一些边和对应点的序列,使得前一条边的终止点等于下一条边的起始点。
简单路径:经过的点不重复的路径
环:一条首尾相连的路径
简单环:一条首尾相连的简单路径
自环:端点在同一点的边
重边:两条端点相同的边
一些概念
子图:点集V的一个子集V’和端点在V’内部的边集E’构成的图(V’,E’)
联通:两点间存在路径
联通图:任意两点都联通的图
顶点的度:点相连的边的个数
点的入度:有向图以该点为终点的边的个数
点的出度:有向图以该点为起点的边的个数
完全图:每一对不同顶点恰有一条边相连的图
一些板子
存储-链式前向星
//链式前向星
void add(int x,int y,int z)
{
to[cnt ++] = y;
v[cnt] = z;
nxt[cnt] = head[x];
head[x] = cnt;
}
//输出所有从x出发的终点和边权
for(int i = head[x];i;i = nxt[i])
printf("%d %d",to[i],v[i]);
图的遍历
//图的遍历:dfs/bfs
void dfs(int x)
{
vis[x] = 1;
printf("%d\n",x);
for(int i = head[i];i;i = nxt[i])
if(!vis[to[i]])
dfs(to[i]);
}
---------------
void bfs(int x)
{
z[top ++] = x;
for(int i = 1;i <= top;i ++)
{
int noe = z[top ++];
printf("%d\n",now);
for(int j = head[now];j;j = nxt[j])
if(!vis[to[j]])
vis[to[j]] = 1,z[top ++] = to[j];
}
}
欧拉路径
//欧拉路径
void dfs(int x)
{
for(int i = head[x];i;i = nxt[i])
if(!vis[i])
vis[i] = 1,dfs(to[i]);
cout << x;
}
拓扑排序
//拓扑排序
for(int i = 1;i <= n;i ++)
if(d[i] == 0)
z[top ++] = i;
for(int i = 1;i <= top;i ++)
{
for(int j = head[z[i]];j;j = nxt[j])
{
d[to[j]] --;
if(d[to[j]] == 0)
z[top ++] = to[j];
}
}
多源最短路
//多源最短路
for(int k = 1;k <= n;k ++)
{
for(int i = 1;i <= n;i ++)
{
for(int j = 1;j <= n;j ++)
f[i][j] = min(f[i][j],f[i][k] + f[k][j]);
}
}
Dijkstra单源
//Dijkstra
struct node
{
int id,dis;
friend bool operator < (node x,node y)
{
return x.dis > y.dis;
}
};
priority_queue <node> q;
memset(dis,0x3f,sizeof(dis))
dis[1] = 0;
q.push({0,0});
while(!q.empty())
{
now = (q.top()).id;
q.pop();
if(vis[now])
continue;
vis[now] = 1;
for(int i = head[now];i;i = nxt[i])
{
if(dis[to[i]] > dis[now] + w[i])
{
dis[to[i]] = dis[now] + w[i];
q.push({to[i],dis[to[i]]});
}
}
}
Spfa单源
//Spfa(他死了)
void spfa()
{
memset(dis,0x3f,sizeof(dis));
dis[s] = 0;
z[top = 1] = s;
for(int i = 1;i <= top;i ++)
{
int now = z[j];
vis[now] = 0;
for(int i = head[now];i;i = nxt[i])
{
if(dis[to[i]] > dis[now] + w[i])
{
dis[to[i]] = dis[now] + w[i];
if(!vis[to[i]])
vis[to[i]] = 1;
z[top ++] = to[i];
}
}
}
}
Tarjan单源
//求割点
void dfs(int u,int fa)
{
low[u] = dfn[u] = dfs_clock ++;
int c = 0;
for(int i = head[u];i;i = nxt[i])
{
int v = to[i];
if(!dfn[v])
{
dfs(v,u);
c ++;
low[u] = min(low[u],low[v]);
if(low[v] >= dfn[u])
cut[u] = 1;
}
else
if(dfn[v] < dfn[u] && v != fa)
low[u] = min(low[u],dfn[v]);
}
if(c == 1 && fa == 0)
cut[u] = 0;
}
//求桥
void tarjan(int u,int fa)
{
dfn[u] = low[u] = dfs_clock ++;
for(int i = head[u];i;i = nxt[i])
{
int v = l[i].t;
if(fa == v)
continue;
if(!dfn[v])
{
tarjan(v,u);
low[u] = min(low[u],low[v]);
if(low[v] > dfn[u])
bcnt ++,bri[l[i].id] = 1;
}
else
if(dfn[v] < dfn[u])
{
low = min(low[u],dfn[v]);
}
}
}
Kruskal
//Kruskal
for(int i = 1;i <= m && cnt < n - 1;i ++)
{
int x = e[i].from,y = e[i].to,z = e[i].w;
int u = find(x),v = find(y);
if(u == v)
continue;
fa[u] = v;
cnt ++;
add(x,y,z);
add(x,y,z);
}
总结
以上板子来自lyn学长A2391833679 的用心整理,表示衷心感谢!本人依照自己的码风稍加修改。
马上就要HL了,希望这佛脚不会让我爆零(doge
本文详细介绍了图论的基础概念,如有向/无向图、完全图等,并涵盖了路径、环、子图、联通性、度量、拓扑排序、最短路径算法(Dijkstra、Spfa)、割点和桥检测(Tarjan)以及Kruskal算法。这些内容是针对IT技术中数据结构和算法的学习资料,为即将到来的考试做准备。
168万+

被折叠的 条评论
为什么被折叠?



