constint N =1e5+10, M =2e5+10;constint INF =0x3f3f3f3f;int head[N], cnt;//初始化voidinit(int n){fill_n(head, n +5,-1); cnt =-1;}structedges{int to, next;int w;voidadd(int t,int n,int w){
to = t, next = n,this->w = w;}}edge[N <<1];//无向图则需要乘2inlinevoidadd(int u,int v,int w){
edge[++cnt].add(v, head[u], w);
head[u]= cnt;}
1. 最短路
dijkstra
constint N =1e5+5, inf =0x3f3f3f3f;int dis[N], vis[N];
vector<pair<int,int>> mp[N];structqnode{int v;int w;qnode(int v =0,int w =0):v(v),w(w){}booloperator<(const qnode &t)const{return w > t.w;}};voiddij(int n,int s){//n 为顶点数, m 为边数for(int i =0; i <= n;++i) dis[i]= inf, vis[i]=0;
dis[s]=0;
priority_queue<qnode> heap;
heap.push(qnode(s, dis[s]));while(heap.size()){int u = heap.top().v;
heap.pop();if(vis[u])continue;
vis[u]=1;for(auto[v, w]: mp[u]){if(!vis[v]&& dis[u]+ w < dis[v]){//松弛
dis[v]= dis[u]+ w;
heap.push(qnode(v, dis[v]));}}}}
bellman-ford
constint N =1e5+10, M =2e5+10, inf =0x3f3f3f3f;int dis[N];structedges{int u, v, w;edges(int u =0,int v =0,int w =0):u(u),v(v),w(w){}} edge[M];boolbf(int n,int m,int s){// n个点, m个边, s为起点fill_n(dis, n +1, inf);
dis[s]=0;for(int k =1; k < n; k++){int ok =1;for(int i =1; i <= m; i++){if(dis[edge[i].v]> dis[edge[i].u]+ edge[i].w){//松弛
dis[edge[i].v]= dis[edge[i].u]+ edge[i].w;
ok =0;}}if(ok)break;// 小优化,无松弛操作}for(int i =1; i <= m; i++){if(dis[edge[i].v]> dis[edge[i].u]+ edge[i].w){returnfalse;// 有负环}}returntrue;// 无负环}
constint M =2e2;int n, m;//顶点数和边数int dis[M][M];voidfloyd(){for(int k =0; k < n; k++){for(int i =0; i < n; i++){for(int j =0; j < n; j++){if(dis[i][j]> dis[i][k]+ dis[k][j]){
dis[i][j]= dis[i][k]+ dis[k][j];}}}}}voidinit(){memset(dis,0x3f,sizeof dis);for(int i =0; i < M;++i) dis[i][i]=0;}
2. 生成树
kruskal 适合稀疏图
#definelllonglongusingnamespace std;#include<cctype>inlinelonglongIO(){}//省略快读constint M =2e5+10, N =5e5+5;int fa[M];structedges{int u, v; ll w;} e[N];boolcmp(edges& i, edges& j){return i.w < j.w;}intfindset(int x){return x == fa[x]? x : fa[x]=findset(fa[x]);}boolun(int a,int b){int fa1 =findset(a), fa2 =findset(b);if(fa1 == fa2)returnfalse;
fa[fa1]= fa2;returntrue;}
ll kruskal(int n,int m){sort(e, e + m, cmp);for(int i =0; i <= n;++i) fa[i]= i;int cnt =0;
ll ans =0;for(int i =0; i < m;++i){if(un(e[i].u, e[i].v)){
ans += e[i].w;if(++cnt == n -1)break;}}return n -1== cnt ? ans :-1;}intmain(){int n =IO(), m =IO();for(int i =0; i < m;++i) e[i].u =IO(), e[i].v =IO(), e[i].w =IO();printf("%lld\n",kruskal(n, m));return0;}
3. tarjan
4. 网络流
Edmonds-Karp算法,速度较慢
classEK{structedges{int to, next;
ll cap, flow;// flow为记录当前路径流的流量,cap为容量};
vector<edges> e;staticconst ll inf =1e18;
vector<int> head, vis, pre;// vis记录是否在队内, pre记录前驱内存池编号
vector<ll> minc;// minc记录增广路的最小流int n;// 点的个数intbfs(int s,int t){
queue<int> q;for(int i =0; i <= n;++i) vis[i]=0, pre[i]=-1;
q.push(s), vis[s]=1, minc[s]= inf;// 初始化minc为无穷大while(q.size()){int u = q.front(); q.pop();for(int i = head[u];~i; i = e[i].next){int v = e[i].to;if(vis[v]|| e[i].cap == e[i].flow)continue;
vis[v]=1, pre[v]= i;
minc[v]=min(minc[u], e[i].cap - e[i].flow);// 更新最小流if(v == t)return1;//找到了终点(汇点)
q.push(v);}}return0;}public:EK(int n =0){init(n);}voidinit(int n){this->n = n;
e.clear();
head.resize(n +1);fill(head.begin(), head.end(),-1);
pre.resize(n +1), vis.resize(n +1), minc.resize(n +1);}voidadd_edge(int u,int v, ll cap,int f =1){
e.push_back({v, head[u], cap,0});
head[u]= e.size()-1;if(f)add_edge(v, u,0,0);}
ll maxflow(int s,int t){// 计算最大流
ll ans =0,&dif = minc[t];while(bfs(s, t)){
ans += dif;for(int i = pre[t];~i; i = pre[e[i ^1].to]){
e[i].flow += dif;// 正向边flow+
e[i ^1].flow -= dif;// 反向边flow-}}return ans;}voidclearflow(){// 将流清空for(auto& x : e) x.flow =0;}};
dinic, 当前弧优化+多路增广优化+炸点优化(模板题),复杂度
O
(
n
2
m
)
O(n^2m)
O(n2m)
classDinic{structedges{int to, next;
ll cap, flow;// flow为记录当前路径流的流量,cap为容量};
vector<edges> e;staticconst ll inf =1e18;
vector<int> head, cur, deep;int n;// bfs求增广路,一次求出多条增广路intbfs(int s,int t){
queue<int> q;for(auto& x : deep) x =0;
deep[s]=1, q.push(s);while(q.size()){int u = q.front(); q.pop();for(int i = head[u];~i; i = e[i].next){int v = e[i].to;if(deep[v]|| e[i].cap == e[i].flow)continue;
deep[v]= deep[u]+1;
q.push(v);}}return deep[t]!=0;}
ll dfs(int u,int t, ll flow){if(u == t)return flow;
ll nowflow =0;for(int i = cur[u];~i; i = e[i].next){
cur[u]= i;// 当前弧优化int v = e[i].to;if(deep[v]!= deep[u]+1|| e[i].cap == e[i].flow)continue;if(ll low =dfs(v, t,min(flow - nowflow, e[i].cap - e[i].flow))){
e[i].flow += low, e[i ^1].flow -= low;
nowflow += low;// 多路增广优化if(nowflow == flow)break;}}if(!nowflow) deep[u]=-2;// 炸点优化return nowflow;}public:Dinic(int n =0){init(n);}voidinit(int n){this->n = n;
e.clear();
head.resize(n +1);fill(head.begin(), head.end(),-1);
deep.resize(n +1);}voidadd_edge(int u,int v, ll cap,int f =1){
e.push_back({v, head[u], cap,0});
head[u]= e.size()-1;if(f)add_edge(v, u,0,0);}
ll maxflow(int s,int t){
ll ans =0;while(bfs(s, t)){
cur = head;// 预处理,方便当前弧优化
ans +=dfs(s, t, inf);// 进过多路增广优化可不用循环}return ans;}voidclearflow(){for(auto& x : e) x.flow =0;}};
int match[M];bool vis[M];booldfs(int u){for(int&v : gp[u]){if(vis[v])continue;
vis[v]=true;if(!match[v]||dfs(match[v])){
match[u]= v, match[v]= u;returntrue;}}returnfalse;}// 主函数里fill_n(match, n +1,0);// n是点的个数for(int i =1; i <= n;++i){if(match[i])continue;fill_n(vis, n +1,false);dfs(i);}