标签:中转 lag 时间复杂度 调试 com 入队 最短路算法 不能 bellman
写在前面:图论题的调试真感人
让我们进入正题
emmm 顾名思义最短路就是求一个点到另外一个点的最小距离
一般来说最短路分为:单源最短路和多源最短路
单源最短路就是求一个源点到另外多个点的最短距离
而多源最短路就是求多个点到其他点的最短距离
算法一般有:
for(int k=1;k<=n;++k)//枚举中转点
for(int i=1;i<=n;++i)//枚举边的起点
for(int j=1;j<=n;++j)//枚举边的终点
if(a[i][j]>a[i][k]+a[k][j])//松弛操作(即利用第三个点来判断是否可以更新目标两个点的最短距离)
a[i][j]=a[i][k]+a[k][j];//a[i][j]是从i到j的最小值
关于k为什么要枚举在第一层循环:
刚才已经说过floyd类似于dp,而k就是dp的阶段(dp的阶段显然要枚举在第一层的),其实a本来是三维a[k][i][j]表示只经过前k个点从i到j的最短路,而可以将第一维的k舍去(like背包) 所以就成了现在的样子啦
void dij(int s){
memset(vis,0,sizeof(vis));
vis[s] = 1;//将s放入S集合
for(int i = 1;i <= n;++i){
if(g[s][i]){dis[i] = g[s][i];}//如果从s到i有路的话 就将s到i的距离设置为长度
else dis[i] = 0x3f3f3f3f;//将其他点设置为正无穷(即目前无法到达)
}
dis[s] = 0;//源点s到自己的最短距离是0
for(int i = 1;i < n;++i){//遍历每一个点以求出每一个点距离源点的最小距离
int Min = 0x3f3f3f3f,k = 0;//Min维护这一轮维护后要放入S集合的距离最小值,k维护要放入S集合的点
for(int j = 1;j <= n;++j)
if(!vis[j] && Min > dis[j]){//如果点j还没有在S集合中并且s到当前节点的距离更小
Min = dis[j];k = j;
}
vis[k] = 1;//k放入S集合
for(int j = 1;j <= n;++j){
if(g[k][j] && dis[j] > dis[k] + g[k][j]){//如果可以通过k松弛
dis[j] = dis[k] + g[k][j];//更新到j的最小值
}
}
}
}
关于优化:
void dij(int x){
priority_queue<node> q;
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[x] = 0;
q.push(node(x,0));
while(!q.empty()){
node t = q.top();q.pop();
int k = t.num;
if(vis[k])continue;
vis[k] = 1;
for(int i = head[k];i;i = a[i].next){
int v = a[i].to;
if(dis[v] > dis[k] + a[i].dis){
dis[v] = dis[k] + a[i].dis;q.push(node(v,dis[k] + a[i].dis));
}
}
}
}
for(int i = 0;i < n;++i)//枚举顶点
for each(i,j)//对于每一条边
song_chi(i,j)//松弛操作
void BF(int u){
memset(d,0x3f,sizeof(d));
d[u] = 0;
for(int i = 1;i < n;++i){
for(int j = 1;j <= cnt;++j){//cnt存的是图中共有几个边
int x = a[j].from,y = a[j].to,z = a[j].dis;
d[y] = min(d[y],d[x] + z);//松弛操作
}
}
}
bool check(){
for(int i = 1;i <= cnt;++i){
int x = a[i].from,y = a[i].to,z = a[i].dis;
if(d[y] < d[x] + z)return 1;
}
return 0;
}
//主函数中:
if(check()){
printf("NO\n");return 0;
}
struct node{
int to,dis,next;
}a[maxn];
void add(int x,int y,int z){
a[++cnt].to = y;a[cnt].next = head[x];a[cnt].dis = z;head[x] = cnt;
}
bool spfa(int s){
memset(dis,0x3f,sizeof(dis));dis[s] = 0;//dis存到源点的最短距离
queue<int>q;
q.push(s);flag[s] = 1;//s入队
while(!q.empty()){
int u = q.front();q.pop();flag[u] = 0;//因为一个节点u可能多次进队
for(int i = head[u];i;i = a[i].next){//邻接表存边
int v = a[i].to;
if(dis[v] > dis[u] + a[i].dis){//松弛操作:没错,还是我!!!
dis[v] = dis[u] + a[i].dis;
if(!flag[v]){//优化
if(++num[v] >= n)return 0;如果同一个点被多次松弛 那么肯定有负环(这个判断也比刚才的少女口阿 把前辈666扣在公屏上)
q.push(v);flag[v] = 1;//v进队,标记
}
}
}
}
return 1;
}
//主函数中:
if(!spfa(源点))输出NO
else 输出距离
好了 本文阅读到此结束了
码字不易 推荐走起
如果您有不懂的地方 或者 您发现代码有问题可以在下方评论或者给博主留言
感谢观看>_<
标签:中转 lag 时间复杂度 调试 com 入队 最短路算法 不能 bellman
原文地址:https://www.cnblogs.com/2004-08-20/p/13232330.html