首页 > 编程语言 >图论算法汇总

图论算法汇总

时间:2024-02-25 21:44:21浏览次数:27  
标签:图论 int 汇总 cnt 算法 dfn low dis

图论算法在信息学竞赛中有着非常广泛的应用, 也频繁在考试与比赛中作为重要的考察知识.本文汇总并分类了信息学竞赛中的图论算法.

1 生成树与最短路

1.1 Prim 算法

Prim 算法可以求出一张图的最小生成树, 时间复杂度为 \(\mathcal{O}((|V|+|E|)\log |V|)\).

memset(dis,0x3f,sizeof(dis));
dis[1] = 0;
q.push({1,0});
while(!q.empty()) {
	if(cnt>=n)break;
	int x=q.top().x,d=q.top().d;
	q.pop();
	if(vis[u])continue;
	vis[u]=1;
    ++cnt;
    res+=d;
    for(auto to:e[x]){
    	int y=to.to,w=to.w;
    	if(w<dis[v])
        	dis[v]=w,q.push({v,w});
    }
}

1.2 Kruskal 算法

Kruskal 算法可以求出一张图的最小生成树, 时间复杂度为 \(\mathcal{O}(|E|\log |E|)\).

sort(e+1,e+m+1,cmp);
int ans=0,cnt=0; 
for(int i=1;i<=m;++i){
    int x=e[i].u,y=e[i].v,z=e[i].w;
    int fx=fd(x),fy=fd(y);
    if(fx==fy)continue;
    fa[fx]=fy;
    ans+=z,cnt++;
    if(cnt==n-1)break;
}

1.3 Dijkstra 算法

Dijkstra 是一种效率优秀的单元最短路算法, 但不能处理负边权. 时间复杂度为 \(\mathcal{O}(|E|\log |E|)\).

memset(d,0x3f,sizeof(dis));
dis[s]=0;
q.push({s, 0});
while(!q.empty()){
	int x=q.top().x;
	q.pop();
	if(vis[x])continue;
	vis[x]=1;
	for(auto to:e[x]){
		int y=to.to,w=to.w;
		if(!vis[y]&&d[y]>d[x]+w){
			d[y]=d[x]+w;
			q.push({x,d[x]});
		}
	}
}

1.4 SPFA 算法

SPFA 可以用于处理存在负边权的最短路问题, 也可以处理最长路问题. SPFA 算法也被常用于对于一个图中负环存在的判定. 最劣时间复杂度为 \(\mathcal{O}(|V||E|)\), 但通常情况下效率较高.

memset(dis,0xff,sizeof(dis));
dis[s]=0,vis[s]=cnt[s]=1;
q.push(s);
while(!q.empty()){
	int x=q.front();
	q.pop();
	vis[x]=0;
	for(auto to:e[x]){
		int y=to.to,w=to.w;
		if(dis[y]>dis[x]+w){
			dis[y]=dis[x]+w;
			if(!vis[y]){
				q.push(y);
				cnt[y]++;
				vis[y]=1;
				if(cnt[y]>n+1)/* 存在负环 */;
			}
		}
	}
}

2 连通性算法

2.1 强联通分量

Tarjan 算法可以用于求有向图的强联通分量 (SCC). 时间复杂度为 \(\mathcal{O}(|V|+|E|)\).

void tarjan(int x)
{
	++_time;
	dfn[x]=low[x]=_time;
	st.push(x);
	vis[x]=1;
	for(int y:e[x])
		if(!dfn[y]){
			tarjan(y);
			low[x]=min(low[x],low[y]);
		}
		else if(vis[y])
			low[x]=min(low[x],dfn[y]);
	if(dfn[x]==low[x]){
		v[x]=0;
		++num;
		id[x]=num;
		sz[num]=1;
		while(st.top()!=x){
			int t=st.top();
			st.pop();
			v[t]=0;
			id[t]=num;
			sz[num]++;
		}
		st.pop();
	}
}

2.2 点双联通分量

Tarjan 算法可以求出无向图的点双联通分量. 时间复杂度为 \(mathcal{O}(|V|+|E|)\).

void tarjan(int x,int fa)
{
	dfn[x]=low[x]=++_time;
	int siz=0;
	s[++top]=x;
	for(int y:e[x])
		if(!dfn[y]){
			siz++;
			tarjan(y,x);
			low[x]=min(low[x],low[y]);
			if(low[y]>=dfn[x]){
				cnt++;
				while(s[top+1]!=y)ans[cnt].push_back(s[top--]);
				ans[cnt].push_back(x);
			}
		}
		else if(y!=fa)low[x]=min(low[x],dfn[y]);
	if(!siz&&x==rt)
		ans[++cnt].push_back(x);
}

2.3 割点

Tarjan 算法可以求出无向图的割点. 时间复杂度为 \(\mathcal{O}(|V|+|E|)\).

void tarjan(int x,int fa)
{
	int son=0;
	dfn[x]=low[x]=++tot;
	for(int i=0;i<e[x].size();++i)
	{
		int y=e[x][i];
		if(y==fa)continue;
		if(!dfn[y])
		{
			son++;
			tarjan(y,x);
			low[x]=min(low[x],low[y]);
			if(low[y]>=dfn[x]&&fa)cnt+=!b[x],b[x]=1;
		}
		else low[x]=min(low[x],dfn[y]);
	}
	if(son>=2&&fa==0)cnt+=!b[x],b[x]=1;
}

2.4 边双联通分量

Tarjan 算法可以求出无向图的边双联通分量, 时间复杂度为 \(\mathcal{O}(|V|+|E|)\).

void tarjan(int x,int edg){
	dfn[x]=low[x]=++_time;
	for (int i=hd[x];i;i=nxt[i]) {
		int y=to[i];
		if(!dfn[y]){
			tarjan(y,i);
			low[x]=min(low[x],low[y]);
			if(low[y]>dfn[x])
				bridge[i]=bridge[i^1]=1;
		}
		else if(i!=(edg^1))
			low[x]=min(low[x],dfn[y]);
	}
}
void dfs(int x) {
	col[x]=dcc;
	if(x)
		ans[dcc].push_back(x); 
	for(int i=hd[x];i;i=nxt[i]) {
		int y=to[i];
		if (col[y]||bridge[i])continue;
		dfs(y);
	}
}

2.5 割边

Tarjan 算法可以求出无向图的割边, 时间复杂度为 \(\mathcal{O}(|V|+|E|)\).

void tarjan(int x,int fa) {
	fat[x]=fa;
  	dfn[x]=low[x]=++_time;
  	for(int y:e[x]){
    	if(!dfn[v]){
      		tarjan(y,x);
      		low[x]=min(low[x],low[y]);
      		if(low[y]>dfn[x]){
        		bridge[y] = true;
        		++cnt;
      		}
    	}else if(dfn[y]<dfn[x]&&y!=fa) {
      		low[u] = min(low[u], dfn[v]);
    	}
 	}
}

2.6 圆方树

3 二分图

3.1 二分图最大匹配

Hungary 算法通常用来解决二分图的最大匹配问题. 时间复杂度为 \(\mathcal{O}(|V||E|)\).

bool dfs(int x,int tag){
	if(v[x]==tag)return 0;
	v[x]=tag;
	for(int i=0;i<e[x].size();++i){
		int y=e[x][i];
		if(!mat[y]||dfs(mat[y],tag)){
			mat[y]=x;
			return 1;
		}
	}
	return 0;
}

3.2 二分图最大权完美匹配

KM 算法用于解决二分图最大权匹配. 时间复杂度为 \(\mathcal{O}(|V|^3)\).

void bfs(int s){
	int x,y,delta,tmp=0;
	y=0;
	memset(pre,0,sizeof(pre));
	for(int i=1;i<=n;++i)d[i]=1e18;
	mat[y]=s;
	while(1){
		x=mat[y];delta=1e18;visy[y]=1;
		for(int i=1;i<=n;++i){
			if(visy[i])continue;
			if(d[i]>la[x]+lb[i]-e[x][i]){
				d[i]=la[x]+lb[i]-e[x][i];
				pre[i]=y;
			}
			if(d[i]<delta)delta=d[i],tmp=i;
		}
		for(int i=0;i<=n;++i){
			if(visy[i])la[mat[i]]-=delta,lb[i]+=delta;
			else d[i]-=delta;
		}
		y=tmp;
		if(mat[y]==-1)break;
	}
	while(y)mat[y]=mat[pre[y]],y=pre[y];
}
int KM(){
	memset(mat,0xff,sizeof(mat));
	memset(la,0,sizeof(la));
	memset(lb,0,sizeof(lb));
	for(int i=1;i<=n;++i){
		memset(visy,0,sizeof(visy));
		bfs(i);
	}
	int res=0;
	for(int i=1;i<=n;++i){
		if(mat[i]!=-1)res+=e[mat[i]][i];
	}
	return res;
}

标签:图论,int,汇总,cnt,算法,dfn,low,dis
From: https://www.cnblogs.com/xuzhanghan/p/18032972

相关文章

  • Python数据结构与算法05——二分查找
    二分查找——递归版:defbinarySearch(aimlist,item):#获取列表的长度n=len(aimlist)#如果列表非空ifn>0:#计算中间索引mid=n//2#如果中间元素是目标元素,则找到了ifaimlist[mid]==item:......
  • 【国产化】禁止使用不安全的密码算法:DES、RC2,RSA(1024位及以下),MD5,SHA1
    一、引言随着互联网的普及和技术的发展,网络安全问题日益严重。密码算法作为网络安全的基石,其安全性直接关系到用户数据的安全。一些不安全的密码算法不断被曝光,给用户带来了极大的安全隐患。二、不安全的密码算法1.DESDES(DataEncryptionStandard)是一种对称加密算法,自1977年......
  • C++U6-05 - 动态规划算法入门
    目标:动态规划     兔子数列的每一项都是前两项之和,公式为f[n]=f[n−1]+f[n−2]。#include<bits/stdc++.h>usingnamespacestd;intmain(){intf[105],n;f[1]=1;f[2]=1;cin>>n;for(inti=3;i<=n;i++){......
  • 前缀和算法
    一、简析前缀和有一系列元素\(A[a_0,~a_1,~...,~a_n,~...]\),前缀和\(pre\_sum[n]=A[0]+A[1]+···+A[n]\)。利用前缀和,我们可以很高效地得到\([L,~R]\)的区间和\(\sum_{i=L}^{R}A[i]=pre\_sum[R]-pre\_sum[L-1]\)。二、相关问题2.1题目简述P8649[蓝桥杯2017省B]......
  • 【机器学习算法】KNN鸢尾花种类预测案例和特征预处理。全md文档笔记(已分享,附代码)
    本系列文章md笔记(已分享)主要讨论机器学习算法相关知识。机器学习算法文章笔记以算法、案例为驱动的学习,伴随浅显易懂的数学知识,让大家掌握机器学习常见算法原理,应用Scikit-learn实现机器学习算法的应用,结合场景解决实际问题。包括K-近邻算法,线性回归,逻辑回归,决策树算法,集成学习,聚......
  • SPFA算法
    一、单源最短路径typedeflonglongll;constintMAX=2e3+5;constllINF=numeric_limits<ll>::max();typedefstruct{ intto,worth;}edge;intn,m;vector<edge>G[MAX];lld[MAX];boolvis[MAX];voidspfa(ints){ fill(d+1,d+1+n,......
  • Airtest:各平台的剪切板功能汇总
    1.前言一直以来,大家都还挺关注 Airtest是否有剪切板功能 的。从Airtest1.3.1版本起,我们新增了Android、iOS设备的剪切板功能,自此,3大平台的剪切板功能就齐全啦。正好趁这个机会,我们给各大平台的剪切板功能做个合集,方便同学们查阅使用~2.Android设备的剪切板功能Android设备的......
  • 2024牛客寒假算法基础集训营6
    A.欧拉筛处理出素数直接3重暴力循环找#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=1e5+10;#defineinf0x3f3f3f3fboolis_prime[N];//是否是质数,0为是,1为不是intprime[N];//质数数组inttop=1;//质数的下标intmin_p[N];//最小......
  • 2024牛客寒假算法基础集训营6 H 纷乱的红线 题解
    Question2024牛客寒假算法基础集训营6H纷乱的红线小红拿到了一个圆,以及平面上有\(n\)个点(保证没有三点共线)。现在小红将随机取\(3\)个点画一个三角形,她想知道这个三角形和圆的交点数量的期望是多少?Solution考虑到\(n\le1000\)可以枚举每一条线,计算这一条线和圆的交......
  • 提高组算法-树状数组
    树状数组是当序列动态变化时,依然可以高效率的查询和维护前缀和(或区间和)的数据结构。实现思路现在有\(16\)个数字:\(a[]={1,8,5,9,6,3,9,8,7,2,3,9,6,4,1,7}\)。我们要实现\(2\)个函数:修改其中某个元素的数值。求出前\(n\)个数字的和。但是,这\(2\)个函数要在极......