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 longusing 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 longusing 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;//}