【HDU 1874 2544 2066 2112】 Dijkstra单源最短路径专题 —— 优先队列+邻接表/邻接矩阵

HDU 1874  畅通工程续

解题报告:

由于顶点(城镇)的数目只有200个,所以可以采用邻接矩阵的形式来存储,代码会更简洁些,也不容易出错。但是处于练习的目的,采用邻接表+优先队列的方式实现,优先队列使用STL中的priority_queue。很基础的单源单汇最短路径。

HDU 2544  最短路

解题报告:

基本和1874是一样的,只是数据量小了,并且要求当n==0 && m==0时终止,值得注意!这道题同时也保证了一定是可达的,所以输出时可以直接输出。

HDU 2066  一个人的旅行

解题报告:

这是一道多源多汇的最短路径问题,要新增一个统一的虚源,记为0(其实就是看成是草儿的家),并且0和其它源的距离都是0,这样就完成了转化。值得注意的是,输入数据是有重边的,如果用邻接矩阵做,要比较去重,邻接表的话,直接做就是了!

HDU 2112  HDU Today

解题报告:

看完题目直接笑喷了,能不要这么逗么!!!其实这题也就是要处理下字符串而已,直接用map映射成整数,映射完后,就跟2544和1874是一样的了。唯一值得注意的就是:start和end是可能一样的!

/// HDU 1874  邻接表+优先队列
#include<iostream>
#include<vector>
#include<queue>
#include<utility>
#include<climits>
using namespace std;
typedef pair<int,int> mp;

int n,m; // n towns and m roads
int S,T; //Source and Terminate
const int maxv=1000+10;
bool vis[maxv];
int dist[maxv];        // dist[i]表示S到i的最短距离
int parent[maxv];      // parent[i]表示S到i的最短路径中i的前一个节点
vector<mp> V[maxv]; //邻接表[i:j1,j2...]和权重w

void dijkstra(int S)
{
    //initial
    for(int i=0;i<maxv;++i) {dist[i]=INT_MAX;vis[i]=false;}
    priority_queue<mp,vector<mp>,greater<mp> > heap;
    dist[S]=0; heap.push(mp(0,S));

    while( !heap.empty() )
    {   //initial
        mp now=heap.top(); heap.pop();//pop掉的是当前所有备选顶点中距离S最近的点
        int u=now.second;//int uCost=now.first;
        if(vis[u]) continue;  vis[u]=true;

        for(int i=0;i<V[u].size();++i)
        {
            int v=V[u][i].second;
            int edgeCost=V[u][i].first;
            if(dist[u]+edgeCost < dist[v]){
                dist[v]=dist[u]+edgeCost ;
                parent[v]=u;
                heap.push(mp(dist[v],v));
            }
        } //for
    }
}
void printPath(int TT)
{
    if(parent[TT]==S)
        cout<<S<<"->"<<TT;
    else{
        printPath(parent[TT]);
        cout<<"->"<<TT;
    }
}

int main()
{
    int v1,v2,w,ans;
    while(cin>>n>>m)
    {
        for(int i=0;i<n;++i) V[i].clear();
        for(int i=0;i<m;++i)
        {
            cin>>v1>>v2>>w;
            V[v1].push_back(mp(w,v2));
            V[v2].push_back(mp(w,v1));
        }
        cin>>S>>T;

        dijkstra(S);
        ans=(dist[T]==INT_MAX?-1:dist[T]);
        cout<<ans<<endl;
    }
}
// HDU 2544 (邻接表+ 优先队列)
#include<iostream>
#include<vector>
#include<queue>
#include<utility>
#include<climits>
using namespace std;
typedef pair<int,int> mp;
struct edge{
    int next,cost;
    edge(){}
    edge(int n,int c):next(n),cost(c){}
};

int n,m; // n towns and m roads
int S,T; //Source and Terminate
const int maxv=1000+1;
int dist[maxv];        // dist[i]表示S到i的最短距离
int previous[maxv];      // prev[i]表示S到i的最短路径中i的前一个节点
vector<edge> V[maxv]; //邻接表[i:j1,j2...]和权重w

int dijkstra(int S,int T)
{
    //initial
    for(int i=1;i<=n;++i) dist[i]=INT_MAX; dist[S]=0;
    priority_queue<mp> heap; heap.push(mp(dist[S],S));

    while( !heap.empty() )
    {
        mp now=heap.top(); heap.pop();//pop掉的是当前所有备选顶点中距离S最近的点
        int nowV=now.second;int nowCost=now.first;
        //if(nowV==T) return dist[T];
        if(nowV!=S && dist[nowV]<= nowCost) continue;//由于顶点的值会更新,旧的会形成冗余
        // dist[nowV]是已经确定了的最小距离,nowCost是当前路径下nowV的距离

        for(int i=0;i<V[nowV].size();++i)
        {
            int nextV=V[nowV][i].next;
            int edgeCost=V[nowV][i].cost;
            if(nowCost+edgeCost < dist[nextV]){
                dist[nextV]=nowCost+edgeCost ;
                previous[nextV]=nowV;
                heap.push(mp(dist[nextV],nextV));
            }
        } //for
    }
    return dist[T];
}

int main()
{
    int v1,v2,w;
    while(cin>>n>>m && n+m)
    {
        for(int i=1;i<=n;++i) V[i].clear();
        for(int i=1;i<=m;++i)
        {
            cin>>v1>>v2>>w;
            V[v1].push_back(edge(v2,w));
            V[v2].push_back(edge(v1,w));
        }
        cout<<dijkstra(1,n)<<endl;
    }
}
/// HDU 2066 (邻接矩阵+优先队列)
#include<iostream>
#include<vector>
#include<queue>
#include<utility>
#include<climits>
using namespace std; //why scanf is better than cin???
typedef pair<int,int> mp;

int S,T; //Source and Terminate
const int maxv=1000+50;
bool vis[maxv];
int dist[maxv];        // dist[i]表示S到i的最短距离
int parent[maxv];      // parent[i]表示S到i的最短路径中i的前一个节点
int mat[maxv][maxv];    //邻接矩阵

void dijkstra(int source)
{
    initial
    for(int i=0;i<maxv;++i) {dist[i]=INT_MAX; vis[i]=false;}
    priority_queue<mp,vector<mp>,greater<mp> > heap;
    dist[source]=0; heap.push(mp(dist[source],source));

    while( !heap.empty() )
    {
        mp now=heap.top(); heap.pop();//pop掉的是当前所有备选顶点中距离S最近的点
        int u=now.second;
        if(vis[u]) continue; //可能重复push同一个u
        vis[u]=true;

        for(int v=1;v<maxv;++v)
            if(!vis[v] && mat[u][v]!=INT_MAX && dist[u]+mat[u][v] < dist[v])
            {   // relax松弛
                dist[v]=dist[u]+mat[u][v] ;
                parent[v]=u;
                heap.push(mp(dist[v],v));
            }
    }
}
void printPath(int TT)
{
    if(parent[TT]==S)
        cout<<S<<"->"<<TT;
    else{
        printPath(parent[TT]);
        cout<<"->"<<TT;
    }
}

int main()
{
    int v1,v2,w;
    int t,s,d,end[maxv]; //t条路径(可重复),d个起点,t个终点
    while(cin>>t>>s>>d)
    {
        初始化邻接矩阵
        for(int i=0;i<maxv;++i)
            for(int j=i;j<maxv;++j)
                mat[i][j]=mat[j][i]=INT_MAX;
        输入
        for(int i=1;i<=t;++i){
            cin>>v1>>v2>>w;
            if(mat[v1][v2]>w)//去重
                mat[v1][v2]=mat[v2][v1]=w;
        }
        for(int i=1;i<=s;++i){
            cin>>v2;
            mat[0][v2]=0; // 多起点,设置统一起点0
        }
        for(int i=0;i<d;++i)
            cin>>end[i]; // 多终点

        dijkstra
        dijkstra(0); int ans=INT_MAX;
        for(int i=0;i<d;++i){
            printPath(end[i]);cout<<endl;
            if(dist[end[i]]<ans) ans=dist[end[i]];
        } //输出最近终点的距离
        cout<<ans<<endl;
    }
}
/// HDU 2066 (邻接表+优先队列)
#include<iostream>
#include<vector>
#include<queue>
#include<utility>
#include<climits>
using namespace std;
typedef pair<int,int> mp;

int n,m; // n towns and m roads
int S,T; //Source and Terminate
const int maxv=1000+10;
bool vis[maxv];
int dist[maxv];        // dist[i]表示S到i的最短距离
int parent[maxv];      // parent[i]表示S到i的最短路径中i的前一个节点
vector<mp> V[maxv]; //邻接表[i:j1,j2...]和权重w

void dijkstra(int S)
{
    //initial
    for(int i=0;i<maxv;++i) {dist[i]=INT_MAX;vis[i]=false;}
    priority_queue<mp,vector<mp>,greater<mp> > heap;
    dist[S]=0; heap.push(mp(0,S));

    while( !heap.empty() )
    {   //initial
        mp now=heap.top(); heap.pop();//pop掉的是当前所有备选顶点中距离S最近的点
        int u=now.second;
        if(vis[u]) continue; vis[u]=true;
        //if(dist[u]< uCost) continue;//由于顶点的值会更新,旧的会形成冗余
        // dist[u]是已经确定了的最小距离,uCost是当前路径下u的距离

        for(int i=0;i<V[u].size();++i)
        {
            int v=V[u][i].second;
            int edgeCost=V[u][i].first;
            if(dist[u]+edgeCost < dist[v]){
                dist[v]=dist[u]+edgeCost ;
                parent[v]=u;
                heap.push(mp(dist[v],v));
            }
        } //for
    }
}
void printPath(int TT)
{
    if(parent[TT]==S)
        cout<<S<<"->"<<TT;
    else{
        printPath(parent[TT]);
        cout<<"->"<<TT;
    }
}

int main()
{
    int v1,v2,w;
    int t,s,d,end[maxv]; //t条路径(可重复),d个起点,t个终点
    while(cin>>t>>s>>d)
    {
        for(int i=0;i<maxv;++i) V[i].clear();
        //输入
        for(int i=1;i<=t;++i){
            cin>>v1>>v2>>w;
            V[v1].push_back(mp(w,v2));
            V[v2].push_back(mp(w,v1));
        }
        for(int i=1;i<=s;++i){
            cin>>v2;
            V[0].push_back(mp(0,v2)); // 多起点,设置统一起点0
        }
        for(int i=0;i<d;++i)
            cin>>end[i]; // 多终点

        dijkstra(0); int ans=INT_MAX;
        for(int i=0;i<d;++i){
            //printPath(end[i]);cout<<endl;
            if(dist[end[i]]<ans) ans=dist[end[i]];
        } //输出最近终点的距离
        cout<<ans<<endl;
    }
}
/// HDU 2112 (邻接矩阵+优先队列)
#include<iostream>
#include<string>
#include<map>
#include<queue>
#include <functional>
#include<climits>
#include<utility>
using namespace std;
typedef pair<int,int> pii;

const int maxv=150+10;
int n,t;
string start,finish,s,e;
map<string,int> mapp;
bool vis[maxv];
int dist[maxv];
//int parent[maxv];
int mat[maxv][maxv];

void dijkstra(int source)
{   // initial
    for(int i=0;i<maxv;++i){dist[i]=INT_MAX; vis[i]=false;}
    priority_queue<pii,vector<pii>,greater<pii> > heap;
    dist[source]=0;heap.push(pii(dist[source],source));

    while( !heap.empty() )
    {
        int u=heap.top().second; heap.pop();
        if(vis[u]) continue;
        vis[u]=true;

        for(int v=0;v<maxv;++v)
        if(!vis[v] && mat[u][v]!=INT_MAX && dist[u]+mat[u][v] < dist[v])
        {
            dist[v]=dist[u]+mat[u][v];
            //parent[v]=u;
            heap.push(pii(dist[v],v));
        }
    }
}

int main()
{
    while(cin>>n && n+1)
    {
        cin>>start>>finish;

        mapp.clear();
        for(int i=0;i<maxv;++i)for(int j=i+1;j<maxv;++j) mat[j][i]=mat[i][j]=INT_MAX;
        int k=0; mapp[start]=k++; mapp[finish]=k++;
        for(int i=0;i<n;++i){
            cin>>s>>e>>t;
            if(!mapp.count(s)) mapp[s]=k++;
            if(!mapp.count(e)) mapp[e]=k++;
            if(t < mat[mapp[s]][mapp[e]])
                mat[mapp[e]][mapp[s]]=mat[mapp[s]][mapp[e]]=t;
        }

        //if(start==finish){cout<<0<<endl;continue;}
        //if(n==0){cout<<-1<<endl;continue;}
        dijkstra(mapp[start]);
        cout<<(dist[mapp[finish]]==INT_MAX?-1:dist[mapp[finish]])<<endl;
    }
    return 0;
}

写在最后:

HDU 2680  Choose the best route

HDU 1385
Minimum Transport Cost

HDU
1548 A strange lift

时间: 2024-10-14 01:25:48

【HDU 1874 2544 2066 2112】 Dijkstra单源最短路径专题 —— 优先队列+邻接表/邻接矩阵的相关文章

Dijkstra单源最短路径

Dijkstra单源最短路径 给定一个带权有向图G=(V,E) ,其中每条边的权是一个非负实数.另外,还给定 V 中的一个顶点,称为源.现在我们要计算从源到所有其他各顶点的最短路径长度.这里的长度是指路上各边权之和.这个问题通常称为单源最短路径问题. 下面给出两个计算单源最短路径的模板. Dijkstra_简化版:时间复杂度O(n^2),不可处理重边图 //计算图的以s点为起点的单源最短路径 //图中节点从1到n编号 //运行dijkstrea之前,需要先把图中两点间的距离保存在dist[i][

Dijkstra 单源最短路径算法

Dijkstra 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法,由计算机科学家 Edsger Dijkstra 于 1956 年构思并于 1959 年发表.其解决的问题是:给定图 G 和源顶点 v,找到从 v 至图中所有顶点的最短路径. Dijkstra 算法采用贪心算法(Greedy Algorithm)范式进行设计.在最短路径问题中,对于带权有向图 G = (V, E),Dijkstra 算法的初始实现版本未使用最小优先

Dijkstra单源最短路径(贪心选择)

贪心算法(又称贪婪算法Greedy):在对问题求解时,总是做出在当前看来是最好的选择.仅是在某种意义上的局部最优解.贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解. 可用贪心算法求解的问题一般有两个重要性质: 1.贪心选择性质 在当前状态下做出最好选择,即局部最优选择,然后再去解决做出这个选择后产生的响应的子问题,通常以自顶向下的方式进行,以迭代的方式做出相继的贪心选择,每做一次贪心选择就将所求问题简化为规模更小的子问题.而在动态规

初学图论-Dijkstra单源最短路径算法基于优先级队列(Priority Queue)的实现

这一次,笔者使用了STL库中的优先级队列(Priority Queue)来完成Dijkstra算法中extract-min()语句(即从未选中的节点中选取一个距离原点s最小的点)的功能.由于优先级队列的插入.删除操作只需要logn的时间花费,因此降低了不少运行时间. 本文使用C++实现了这一基本算法.参考<算法导论>第24.3节. /**  * Dijkstra's Single Source Shortest Path Algorithm in C++  * Time Cost : O(Ml

Dijkstra 单源最短路径

1. #include <cstdio> #include <iostream> #include <algorithm> #include <queue> #include <stack> #include <climits> #include <cstring> #include <cmath> #include <map> #include <set> #define INF 10

初学图论-Dijkstra单源最短路径算法

当图中所有边的权重为非负值时,我们可以选用巧妙Dijkstra算法. 本文使用C++实现了这一基本算法.参考<算法导论>第24.3节. 不过在算法的实现中,取当前与原点s最近的节点操作时,采用了线性扫描的策略.如果换用堆或者优先级队列会好很多. /**  * Dijkstra's Single Source Shortest Path Algorithm in C++  * Time Cost : O(N^2)  * Thanks to Introduction to Algorithms (

Dijkstra算法求单源最短路径

1.最短路径 在一个连通图中,从一个顶点到另一个顶点间可能存在多条路径,而每条路径的边数并不一定相同.如果是一个带权图,那么路径长度为路径上各边的权值的总和.两个顶点间路径长度最短的那条路径称为两个顶点间的最短路径,其路径长度称为最短路径长度. 最短路径在实际中有重要的应用价值.如用顶点表示城市,边表示两城市之间的道路,边上的权值表示两城市之间的距离.那么城市A到城市B连通的情况下,哪条路径距离最短呢,这样的问题可以归结为最短路径问题. 求最短路径常见的算法有Dijkstra算法和Floyd算法

Bellman-Ford 单源最短路径算法

Bellman-Ford 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法.该算法由 Richard Bellman 和 Lester Ford 分别发表于 1958 年和 1956 年,而实际上 Edward F. Moore 也在 1957 年发布了相同的算法,因此,此算法也常被称为 Bellman-Ford-Moore 算法. Bellman-Ford 算法和 Dijkstra 算法同为解决单源最短路径的算法.对于带权有向

Dijkstra算法(求单源最短路径)

问题描述 单源最短路径问题,即在图中求出给定顶点到其它任一顶点的最短路径. 最短路径的最优子结构性质 该性质描述为:如果P(i,j)={Vi....Vk..Vs...Vj}是从顶点i到j的最短路径,k和s是这条路径上的一个中间顶点,那么P(k,s)必定是从k到s的最短路径.下面证明该性质的正确性. 性质证明:用反证法易证. Dijkstra算法实现 ps:用连接矩阵int matrix[][]储存边长关系.int dist[2...n]  储存原点1到其他点(2,3...n)的最短距离的"估计值