挑战程序设计竞赛2上的一道例题
P250
#include<iostream>
using namespace std;
static const int MAX = 100;
static const int INFTY = (1<<21); /这里表示int类型最大值
static const int WHITE = 0;//表示三种状态
static const int GRAY = 1;
static const int BLACK = 2;
//点的个数和邻接矩阵存储方式
int n, M[MAX][MAX];
void dijkstra()
{
int minv;
//最短路径和每个点状态的存储结构
int d[MAX], color[MAX];
//初始化
for(int i = 0; i < n; i++)
{
d[i] = INFTY;
color[i] = WHITE;
}
//从零开始到每个点的最短路径
d[0] = 0;
color[0] = GRAY;
//不断循环直至所有点包含在内即color[i]的状态全为BLACK
while(1)
{
minv = INFTY;
int u = -1;
//求出距离0点最短路径并记录下标
for( int i = 0; i < n; i++ )
{
if(minv > d[i] && color[i] != BLACK)
{
u = i;
minv = d[i];
}
}
//状态全为BLACK结束循环
if(u == -1) break;
color[u] = BLACK;
//更新到每个点的最短路径d[i]
for(int v = 0; v < n; v++)
{
if(color[v] != BLACK && M[u][v] != INFTY)
{
if(d[v] > d[u] + M[u][v])
{
d[v] = d[u] + M[u][v];
color[v] = GRAY;
}
}
}
}
//按要求输出
for (int i = 0; i < n; i++ )
{
cout<< i <<" "<<(d[i] == INFTY ? -1: d[i]) << endl;
}
}
int main()
{
cin>>n;
//初始化邻接矩阵
for( int i = 0; i < n; i++ )
{
for( int j = 0; j < n; j++ )
{
M[i][j] = INFTY;
}
}
int k, c, u, v;
for( int i = 0; i < n; i++ )
{
cin >> u >> k;
for( int j = 0; j < k; j++)
{
cin>>v>>c;
M[u][v] = c;
}
}
dijkstra();
return 0;
}
本算法不具有代表性,狄克斯特拉算法模板还有待更新,这pain文章还会继续更新…
一月十二日更新
spfa算法
题目链接点我
- SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环。SPFA最坏情况下复杂度和朴素 Bellman-Ford 相同,为 O(VE)。
- 可作为基础模板的代码如下:
#include<bits/stdc++.h>
const int inf=(1<<20);
const int maxn=10005;
const int maxm=500005;
using namespace std;
int n,m,s,cnt=0;
//head[u],u是指点的编号,head[u]的值是与u邻接的边的编号
int dis[maxn],vis[maxn],head[maxm];
struct Edge
{
int next,to,dis;//上一条边的编号,本结点的编号,本条边的权值
}edge[maxm]; //结构体表示静态邻接表
void add(int from,int to,int dis) //邻接表建图
{ //以下是链式前向星存图的标准代码
edge[++cnt].next=head[from]; //链式存储下一条出边
edge[cnt].to=to; //当前节点编号
edge[cnt].dis=dis; //本条边的权值
head[from]=cnt; //记录下一次的出边情况
}
void spfa()
{
queue<int> q; //spfa用队列,这里用了STL的标准队列
for(int i=1; i<=n; i++)
{
dis[i]=inf; //带权图初始化
vis[i]=0; //记录点i是否在队列中,同dijkstra算法中的visited数组
}
q.push(s); dis[s]=0; vis[s]=1; //第一个顶点入队,进行标记
while(!q.empty())
{
int u=q.front(); //取出队首
q.pop(); vis[u]=0; //出队标记,这里必须出队因为本算法是对所有邻接点到其他点的距离做更换
for(int i=head[u]; i; i=edge[i].next) //邻接表遍历,不多解释了(也可用vector代替)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].dis) //如果有最短路就更改
{
dis[v]=dis[u]+edge[i].dis;
if(vis[v]==0) //未入队则入队
{
vis[v]=1; //标记入队
q.push(v);
}
}
}
}
}
int main()
{
cout<<inf<<endl;
cin>>n>>m>>s;//n个点,m条边,s为开始顶点
for(int i=1; i<=m; i++)
{
int f,g,w;
cin>>f>>g>>w;
add(f,g,w); //建图,有向图连一次边就可以了
}
spfa(); //开始跑spfa
for(int i=1; i<=n; i++)
if(s==i) cout<<0<<" "; //如果是回到自己,直接输出0
else cout<<dis[i]<<" "; //否则打印最短距离
return 0;
} //结束
链式前向星存图方法看上一篇文章