Dijkstra[两种邻接表+优先队列优化]

Dijksta算法中,如果我们采用的是邻接矩阵来存的,第一点浪费的空间比较多,第二点我们知道算法的时间复杂度在O(n*n),这样的算法可以说并不是很好,所以我们考虑优化它首先我们可以优化存储结构,采用邻接表来存储,其次我们可以用优先队列来排序大小,其时间复杂度大大降低。

需要注意的是pair是按照第一个元素的大小排序,如果相同才按照第二个,所以我们要把d[i]包装在第一个元素上。

vector实现邻接表+优先队列 (假设边一开始是字符型的,这么假设是为了加点难度)

#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<queue>
#include<string>
#include<cstring>
#define inf 0x7fffffff
using namespace std;
const int MAXN = 205;
int dis[MAXN];
int n;  //顶点数目
int m;  //边的条数
string src,ed; //src是源点,ed是目标点
typedef pair<int,int> pii;
struct edge //建立边的结构体
{
    int u;
    int v;
    int w;
    edge(int a,int b,int c) //构造函数,建立结构体的时候直接调用这个函数,方便了一个一个赋值。
    {
        u = a;
        v = b;
        w = c;
    }
};
map<string,int>M; //利用map关联容器为字符串型的边进行标号
vector<edge> G[MAXN];//邻接表
void init()
{
    M.clear();//每次循环要对map清空
    int cnt=0;
    cin>>n>>m;
    string u,v;//字符型顶点
    int w;//权值
    for(int i=1;i<=m;i++){
        cin>>u>>v>>w;
        if(!M.count(u))
            M.insert(make_pair(u,++cnt));  //make_pair不仅可以用在pair<>的插入中也可用在map,vector等容器中
        if(!M.count(v))
            M.insert(make_pair(v,++cnt));   //利用map关联容器为字符串型的边进行标号,1,2,3...注意A不一定是1号边,最先读入的才是1号边。
        edge E1(M[u],M[v],w);  //建立无向边,调用构造函数,简洁。
        edge E2(M[v],M[u],w);
        G[M[u]].push_back(E1); //建立邻接表
        G[M[v]].push_back(E2);
    }
    cin>>src>>ed;
    for(int i =1;i<=n;i++) dis[i] = (i == M[src] ? 0 : inf);//初始化dis
}
void dijktra()
{
    priority_queue<pii> que;//优先队列是默认小元素先出队
    que.push(make_pair(0,M[src]));//将起点插入队列,pair默认是优先处理first元素,故插入优先队列先弹出队列的优先级是依据dis[]大小
    while(!que.empty())
    {
        pii tmp = que.top();
        que.pop();
        int x = tmp.second;
        if(tmp.first != dis[x]) continue;     //可避免结点的重复拓展,这里每一个元素出队都相当于处理一次已标号结点,如果出队的这个元素,
                                           //他带的dis,和当前的dis不相同,证明这个结点是被处理过的,这样就不需用开一个数组来标记哪些点被处理过了。
        for(int  i = 0;i < G[x].size();i++)
        {
            int y = G[x][i].v;
            int w = G[x][i].w;
            if(dis[x]!=inf&&dis[y] > dis[x] + w)
            {
                dis[y] = dis[x] + w;
                que.push(make_pair(dis[y],y));
            }
        }
    }
}
int main()
{
   // freopen("1.in","r",stdin);
    int _;
    cin>>_;
    while(_--){
        init();
        dijktra();
        if(dis[M[ed]]==inf) cout<<"-1"<<endl;
        else cout<<dis[M[ed]]<<endl;
        /*输出源点依次到ABC的距离,不能直接把dis按顺序输出,否则可读性差,因为A点不一定是1号点,1号点是最先读入的点,所以利用map以对点A,B,C依排序,*/
        for(map<string,int>::iterator it=M.begin();it!=M.end();it++) printf("%d ",dis[it->second]);
        putchar('\n');
    }
    return 0;
}

输入数据:

1

6 9

D E 13

B C 9

A B 1

A C 12

B D 3

E C 5

D C 4

D F 15

E F 4

A F

输出数据:

17

0 1 8 4 13 17

数组实现邻接表+优先队列

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x7fffffff
using namespace std;
const int MAXN = 205;
int dis[MAXN];
int u[MAXN],v[MAXN],w[MAXN];
int first[MAXN],next[MAXN];
int n,m;
int src,ed;
typedef pair<int,int> pii;
void init()
{
    scanf("%d%d",&n,&m);
    memset(first,-1,sizeof(first));
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&u[i],&v[i],&w[i]);
        next[i]=first[u[i]];
        first[u[i] ]=i;
        u[i+m]=v[i],v[i+m]=u[i],w[i+m]=w[i];  //无向边,所以加一条反向边
        next[i+m]=first[u[i+m] ];
        first[u[i+m] ]=i+m;
    }
    cin>>src>>ed;
    for(int i=1;i<=n;i++) dis[i]= (i==src? 0:inf);//不要把dis[i]初始化成源点到各点的直接距离,否则会有点没入队。
}
void dijkstra()
{
    priority_queue<pii>que;
    que.push(make_pair(0,src));
    while(!que.empty()){
        pii tmp=que.top();
        que.pop();
        int x = tmp.second;
        if(tmp.first!=dis[x]) continue;  //如果出队的这个元素,他带的dis,和当前的dis不相同,证明这个结点是被处理过的已确定了最短路,
        for(int e=first[x];e!=-1;e=next[e]){   //这种数组式邻接表的遍历
            if(dis[x]!=inf&&dis[v[e]]>dis[x]+w[e]){
                 dis[v[e] ]=dis[x]+w[e];
                 que.push(make_pair(dis[v[e] ],v[e]));
            }
        }
    }

}
int main()
{
 //   freopen("1.in","r",stdin);
    int _;
    scanf("%d",&_);
    while(_--){
        init();
        dijkstra();
        if(dis[ed]==inf) cout<<"-1"<<endl;
        else cout<<dis[ed]<<endl;
        for(int i=1;i<=n;i++) printf("%d ",dis[i]);//输出dist数组各个值
        putchar('\n');
    }
}

测试数据:

1

6 9

1 2 1

1 3 12

2 3 9

2 4 3

5 3 5

4 3 4

4 5 13

4 6 15

5 6 4

1 6

输出:

17

0 1 8 4 13 17

时间: 2024-10-09 20:56:18

Dijkstra[两种邻接表+优先队列优化]的相关文章

POJ3159 Dijkstra+邻接表+优先队列

今天学习到了一种新姿势,用邻接表+优先队列优化Dijkstra,这样时间复杂度就由O(N^2+E)变为O(NlogN+E),妈妈再也不用担心我超时了!~\(^o^)/ Candies Time Limit: 1500MS   Memory Limit: 131072K Total Submissions: 25077   Accepted: 6810 Description During the kindergarten days, flymouse was the monitor of his

图论——最小生成树prim+邻接表+堆优化

今天学长对比了最小生成树最快速的求法不管是稠密图还是稀疏图,prim+邻接表+堆优化都能得到一个很不错的速度,所以参考学长的代码打出了下列代码,make_pair还不是很会,大体理解的意思是可以同时绑定两种元素(和struct差不多)但加入堆的时候以第一个元素来进行优先队列,建立的是大根堆由于每次要选出最小的边所以把边取反,最小的那个边加上符号就变成最大的了,大体上就是这样.prim的思想. #include<iostream> #include<cstdio> #include&

POJ 2387 Til the Cows Come Home dijkstra算法 用邻接表和邻接矩阵

题目如下: Til the Cows Come Home Time Limit: 1000MS        Memory Limit: 65536K Total Submissions: 27726        Accepted: 9353 Description Bessie is out in the field and wants to get back to the barn to get as much sleep as possible before Farmer John wa

[转] 两种自定义表单设计方案

无涯 原文 两种自定义表单设计方案 [原创] 2006-12 最近参与一个项目,客户要求提供自定义表单的功能.主要的要求是:能够对表单的字段进行增删改,对显示表单的格式可以灵活定制.由于客户的表单变动可能比较频繁,所以决定实现自定义表单功能.初步设想出以下两种自定义表单的解决方案,目前只涉及到表单的显示方案. 请大家讨论一下两种方案的优劣,使用哪种较好.也欢迎大家提出更好的解决方案. HTML模板方案 概述:采用HTML模板方式.对于每一种样式的表单定义HTML模板:在模板中定义Web页面的HT

关于如何记录数据更改记录的两种建表方式

title: 关于如何记录数据更改记录的两种建表方式 date: 2018-08-08 22:07:44 tags: 数据库 --- 当时要做的一个项目要包含一个权限管理功能,以为该系统中的所有人分配权限.而且这个权限管理的需求是可以把权限接近无限的下发(我感觉现实中是不会无限下发的(.???)ノ),这些都先不讲.因为有权限管理就涉及到用户分组的变动,权限的使用等,但是这些操作都是应该要记录下来的.于是有了两种方案. 1.通过一张单独的事件记录表来记录事件: id uid eventid eti

图基本算法 最小生成树 Prim算法(邻接表+优先队列STL)

这篇文章是对<算法导论>上Prim算法求无向连通图最小生成树的一个总结,其中有关于我的一点点小看法. 最小生成树的具体问题可以用下面的语言阐述: 输入:一个无向带权图G=(V,E),对于每一条边(u, v)属于E,都有一个权值w. 输出:这个图的最小生成树,即一棵连接所有顶点的树,且这棵树中的边的权值的和最小. 举例如下,求下图的最小生成树: 这个问题是求解一个最优解的过程.那么怎样才算最优呢? 首先我们考虑最优子结构:如果一个问题的最优解中包含了子问题的最优解,则该问题具有最优子结构. 最小

poj3013 邻接表+优先队列+Dij

把我坑到死的题 开始开题以为是全图连通是的最小值 ,以为是最小生成树,然后敲了发现不是,看了下别人的题意,然后懂了: 然后发现数据大,要用邻接表就去学了一下邻接表,然后又去学了下优先队列优化的dij: 这坑爹的题目我交了10几遍,也不知道错在哪里:后来知道了maxint要#define Maxint 10000000000: 然后long int 是过不了的,改成long long才能过 ,真是呵呵啊: 1 #include<stdio.h> 2 #include<string.h>

(转)图算法单源最短路径Dijkstra算法(邻接表/邻接矩阵+优先队列STL)

一.前言 最短路径算法,顾名思义就是求解某点到某点的最短的距离.消耗.费用等等,有各种各样的描述,在地图上看,可以说是图上一个地点到达另外一个地点的最短的距离.比方说,我们把地图上的每一个城市想象成一个点,从一个城市到另一个城市的花费是不一样的.现在我们要从上海去往北京,需要考虑的是找到一条路线,使得从上海到北京的花费最小.有人可能首先会想到,飞机直达啊,这当然是时间消耗最小的方法,但是考虑到费用的高昂,这条线路甚至还不如上海到北京的高铁可取.更有甚者,假设国家开通了从上海到西藏,再从西藏到兰州

【Django】Django—Form两种解决表单数据无法动态刷新的方法

一.无法动态更新数据的实例 1. 如下,数据库中创建了班级表和教师表,两张表的对应关系为"多对多" 1 from django.db import models 2 3 4 class Classes(models.Model): 5 title = models.CharField(max_length=32) 6 7 8 class Teacher(models.Model): 9 name = models.CharField(max_length=32) 10 t2c = mo