图论基础
Cody_To_FEB_D · · 算法·理论
图论
小结
存图(2023.6.2
主要有三种方式
- 直接用结构体数组存边
注意根据题目要求设置结构体中的变量
数组大小MAXM
- 邻接表 注意add函数中传输变量不要重名
也注意这两句的先后
e[cnt].nxt=head[u];
head[u]=cnt;
数组大小MAXM
- 邻接矩阵
注意题目的数据范围,一旦n>5000就基本会爆内存,所以大多数情况下都用邻接表存图
数组大小MAXN*MAXN
并查集(2023.6.2
(虽然这好像不是图论的内容,但对于MST相关问题比较有 用)
大家应该都很熟悉,主要注意一些优化
find函数压缩路径
每次搜索时压缩遍历路径,下一次查询时就可以用更短的时间找到所属的集合
int fa[MAXN];
void Create()
{
for(int i=1;i<=n;i++){fa[i]=i;}
}
int find(int x)
{
if(fa[x]!=x) x=fa[x]=find(fa[x]);
return x;
}
merge函数考虑深度
在合并集合时,考虑树结构的深度,矮接高,这样在合并之后深度会尽量小,查询时也就越快
int fa[MAXN];
int d[MAXN];
void Create()
{
for(int i=1;i<=n;i++){fa[i]=i;d[i]=1;}
}
int find(int x)
{
if(fa[x]!=x) x=fa[x]=find(fa[x]);
return x;
}
void merge(int x,int y)
{
int ux,uy;
ux=find(x);uy=find(y);
if(d[ux]>d[uy]){fa[y]=x;d[y]=d[x];}
if(d[ux]==d[uy]){fa[x]=y;d[y]++;d[x]=d[y];}
if(d[ux]<d[uy]){fa[x]=y;d[x]=d[y];}
return;
}
更多见发的资料
最小生成树MST(2023.6.2
个人主要用kruskal算法
这种算法用结构体数组存边,主要思路运用了贪心的思想,并查集,快排。
通过排序来保证贪心,每条加入的边最小,即每条在树里和的边最小
通过并查集来判断任意两点是否联通,即是否在已经树中
由于树的特性,所以生成n-1条边后就已经生成了将所有点联通的最小生成树
//存图
struct EDGE
{
int u,v,w;
}edge[MAXM];
//并查集
int fa[MAXN];
void Create(){for(int i=1;i<=n;i++){fa[i]=i;}}
int find(int x)
{
if(fa[x]!=x) x=fa[x]=find(fa[x]);
return x;
}
//cmp
bool cmp(EDGE x,EDGE y){return x.w<y.w;}
int ans=0;//生成树每条边的权值之和
void kruskal()
{
int tot=0;
sort(edge+1,edge+m+1,cmp);
for(int i=1;i<=m;i++)
{
int u,v;
u=find(edge[i].u);
v=find(edge[i].v);
if(u==v) continue;//如果已经联通则继续枚举
fa[u]=v;
ans+=edge[i].t;
if(++tot==n-1) break;//已经生成n-1条边则跳出循环
}
return;
}