646 字
3 分钟
7-1图论

7-1 图论#

树的直径#

我看网上的博客。 一般树的直径可以跑一遍深度,然后从深度最大的开始跑一下最远的,这个方法还可以把树的直径上的点拿出来

ve<ve<int>>ed(n+1);
ve<int>dis(n+1);
int ls,rs,maxl,maxr;
void dfs1(int u,int la)
{
dep[u]=dep[la]+1;
if(maxl<dep[u])
{
maxl=dep[u];
ls=u;
}
for(auto v:ed[u])
{
if(v==la) continue;
dfs1(v,u);
}
}
void dfs2(int u,int la)
{
dis[u]=dis[la]+1;
if(maxr<dis[u])
{
maxr=dis[u];
rs=u;
}
for(auto v:ed[u])
{
if(v==la) continue;
fa[v]=u;//处理前缀
dfs2(v,u);
}
}
//ls,rs 就是树的直径的两个端点
ls,rs
//拿出树的直径上的端点
ve<int>f;
while(rs!=ls)
{
f.push_back(rs);
rs=fa[rs];
}
f.push_back(ls);

树的中心#

树的重心#

单源最短路(djstka)#

struct node
{
int x,ds;
};
struct cmp
{
bool operater()(node a,node b)
{
return a.ds>b.ds;//当a.ds>b.ds时交换,这个时小顶堆
}
};
ve<ve<int>>ed[N];
ve<int>st[N];
void djs()
{
priority_queue<node,ve<node>,cmp>pq;
pq.push({});
while(pq.size())
{
auto [u,ds]=pq.top();pq.pop();
if(st[u]) continue;
st[u]=1;
for(auto [v,w]:ed[u])
{
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
pq.push({v,dis[v]});
}
}
}
}

分层最短路也是常用的 ,分层图最短路

多源最短路#

floyd (O(n^3) 三层暴力跑最短路)

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define fix(x) fixed<<setprecision(x)
#define int long long
using namespace std;
using ll = long long;
template<class T>
using ve = vector<T>;
using pii = pair<int, int>;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
int n,m,q;
int a[N][N];
void solve()
{
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j) a[i][j]=0;
else a[i][j]=1e18;
}
}
for(int i=1;i<=m;i++)
{
int u,v,w;cin>>u>>v>>w;
a[u][v]=min(a[u][v],w);
}
for(int k=1;k<=n;k++)
{//k是分割点
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
}
}
}
while(q--)
{
int x,y;cin>>x>>y;
if(a[x][y]>=1e9/2 )cout<<"impossible"<<'\n';
else cout<<a[x][y]<<'\n';
}
}
signed main()
{
IOS;
int _ = 1; //cin >> _;
while (_--) solve();
return 0;
}

最小生成树(并查集)#

/*
克鲁斯卡尔算法
是并查集维护的,把边存一下,然后每次拿最小的边权,
如果不会形成环加上,反之舍弃此边。
*/
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define fix(x) fixed<<setprecision(x)
#define int long long
using namespace std;
using ll = long long;
template<class T>
using ve = vector<T>;
using pii = pair<int, int>;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
struct node
{
int a,b,c;
};
bool cmp(node x,node y)
{
return x.c<y.c;
}
int f[N];
int find(int x)
{
if(f[x]!=x) f[x]=find(f[x]);
return f[x];
}
void solve()
{
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++) f[i]=i;
ve<node>a;
for(int i=1;i<=m;i++)
{
int u,v,w;cin>>u>>v>>w;
a.push_back({u,v,w});
}
sort(a.begin(),a.end(),cmp);
int ans=0;
int res=0;
for(int i=0;i<a.size();i++)
{
auto [u,v,w]=a[i];
u=find(u),v=find(v);
if(u==v) continue;
f[u]=v;
ans+=w;
res++;
}
if(res!=n-1) cout<<"orz\n";
else cout<<ans<<'\n';
}
signed main()
{
IOS;
int _ = 1; //cin >> _;
while (_--) solve();
return 0;
}

基环树#

基环树是n个节点,n条边的数据结构,基环树有一个环

有向边的基环树,指向环的是内向树,反之是外向树

dfs找环

set<int>se;
void dfs_c(int u,int la)
{
//st标记是否遍历,ins表示是否在栈中//
st[u]=ins[u]=true;
for(auto v:ed[u])
{
if(st[v]) continue;
fa[v]=u;
dfs_c(v,u);
if(ins[v]) //在栈中,这个感觉是找即环树的一种方式
{//找到环
//拿出环
int id=u;
se.insert(v);
while(id!=v)
{
se.insert(id);
id=fa[id];
}
break;
//
}
}
ins[u]=false;//
}

7-1图论
https://fuwari.vercel.app/posts/7-1图论/
作者
nszkay
发布于
2026-01-07
许可协议
CC BY-NC-SA 4.0