最短路模板【kb大神原创】


1、最短路
1.1	Dijkstra单源最短路,邻接矩阵形式
权值必须是非负
/*
 * 单源最短路径,Dijkstra算法,邻接矩阵形式,复杂度为O(n^2)
 * 求出源beg到所有点的最短路径,传入图的顶点数,和邻接矩阵cost[][]
 * 返回各点的最短路径lowcost[], 路径pre[].pre[i]记录beg到i路径上的父结点,pre[beg]=-1
 * 可更改路径权类型,但是权值必须为非负
 *
 */
const int MAXN=1010;
#define typec int
const typec INF=0x3f3f3f3f;//防止后面溢出,这个不能太大
bool vis[MAXN];
int pre[MAXN];
void Dijkstra(typec cost[][MAXN],typec lowcost[],int n,int beg)
{
	for(int i=0;i<n;i++)
	{
		lowcost[i]=INF;vis[i]=false;pre[i]=-1;
	}
	lowcost[beg]=0;
	for(int j=0;j<n;j++)
	{
		int k=-1;
		int Min=INF;
		for(int i=0;i<n;i++)
			if(!vis[i]&&lowcost[i]<Min)
			{
				Min=lowcost[i];
				k=i;
			}
		if(k==-1)break;
		vis[k]=true;
		for(int i=0;i<n;i++)
			if(!vis[i]&&lowcost[k]+cost[k][i]<lowcost[i])
			{
				lowcost[i]=lowcost[k]+cost[k][i];
				pre[i]=k;
			}
	}
}

1.2	Dijkstar算法+堆优化
使用优先队列优化,复杂度O (E log E)
/*
 * 使用优先队列优化Dijkstra算法
 * 复杂度O(ElogE)
 * 注意对vector<Edge>E[MAXN]进行初始化后加边
 */
const int INF=0x3f3f3f3f;
const int MAXN=1000010;
struct qnode
{
	int v;
	int c;
	qnode(int _v=0,int _c=0):v(_v),c(_c){}
	bool operator <(const qnode &r)const
	{
		return c>r.c;
	}
};
struct Edge
{
	int v,cost;
	Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
};
vector<Edge>E[MAXN];
bool vis[MAXN];
int dist[MAXN];
void Dijkstra(int n,int start)//点的编号从1开始
{
	memset(vis,false,sizeof(vis));
	for(int i=1;i<=n;i++)dist[i]=INF;
	priority_queue<qnode>que;
	while(!que.empty())que.pop();
	dist[start]=0;
	que.push(qnode(start,0));
	qnode tmp;
	while(!que.empty())
	{
		tmp=que.top();
		que.pop();
		int u=tmp.v;
		if(vis[u])continue;
		vis[u]=true;
		for(int i=0;i<E[u].size();i++)
		{
			int v=E[tmp.v][i].v;
			int cost=E[u][i].cost;
			if(!vis[v]&&dist[v]>dist[u]+cost)
			{
				dist[v]=dist[u]+cost;
				que.push(qnode(v,dist[v]));
			}
		}
	}
}
void addedge(int u,int v,int w)
{
	E[u].push_back(Edge(v,w));
}

1.3	单源最短路 bellman_ford算法

/*
 * 单源最短路bellman_ford算法,复杂度O(VE)
 * 可以处理负边权图。
 * 可以判断是否存在负环回路。返回true,当且仅当图中不包含从源点可达的负权回路
 * vector<Edge>E;先E.clear()初始化,然后加入所有边
 * 点的编号从1开始(从0开始简单修改就可以了)
 */
const int INF=0x3f3f3f3f;
const int MAXN=550;
int dist[MAXN];
struct Edge
{
	int u,v;
	int cost;
	Edge(int _u=0,int _v=0,int _cost=0):u(_u),v(_v),cost(_cost){}
};
vector<Edge>E;
bool bellman_ford(int start,int n)//点的编号从1开始
{
	for(int i=1;i<=n;i++)dist[i]=INF;
	dist[start]=0;
	for(int i=1;i<n;i++)//最多做n-1次
	{
		bool flag=false;
		for(int j=0;j<E.size();j++)
		{
			int u=E[j].u;
			int v=E[j].v;
			int cost=E[j].cost;
			if(dist[v]>dist[u]+cost)
			{
				dist[v]=dist[u]+cost;
				flag=true;
			}
		}
		if(!flag)return true;//没有负环回路
	}
	for(int j=0;j<E.size();j++)
		if(dist[E[j].v]>dist[E[j].u]+E[j].cost)
			return false;//有负环回路
	return true;//没有负环回路
}

1.4	单源最短路SPFA

/*
 * 单源最短路SPFA
 * 时间复杂度 0(kE)
 * 这个是队列实现,有时候改成栈实现会更加快,很容易修改
 * 这个复杂度是不定的
 */
const int MAXN=1010;
const int INF=0x3f3f3f3f;
struct Edge
{
	int v;
	int cost;
	Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
};
vector<Edge>E[MAXN];
void addedge(int u,int v,int w)
{
	E[u].push_back(Edge(v,w));
}
bool vis[MAXN];//在队列标志
int cnt[MAXN];//每个点的入队列次数
int dist[MAXN];
bool SPFA(int start,int n)
{
	memset(vis,false,sizeof(vis));
	for(int i=1;i<=n;i++)dist[i]=INF;
	vis[start]=true;
	dist[start]=0;
	queue<int>que;
	while(!que.empty())que.pop();
	que.push(start);
	memset(cnt,0,sizeof(cnt));
	cnt[start]=1;
	while(!que.empty())
	{
		int u=que.front();
		que.pop();
		vis[u]=false;
		for(int i=0;i<E[u].size();i++)
		{
			int v=E[u][i].v;
			if(dist[v]>dist[u]+E[u][i].cost)
			{
				dist[v]=dist[u]+E[u][i].cost;
				if(!vis[v])
				{
					vis[v]=true;
					que.push(v);
					if(++cnt[v]>n)return false;
					//cnt[i]为入队列次数,用来判定是否存在负环回路
				}
			}
		}
	}
	return true;
}


点击打开链接

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值