hdu 2066最短路 dijkstra 及其优先队列优化

http://acm.hdu.edu.cn/showproblem.php?pid=2066

一开始想运用跟之前soj的办法,就是把每个起点都进行一次dijkstra,然后记录下每个顶点下的最短路。。后来发现其实对于车站可以看做与起点之间有一条权值为0的边,那么这样就可以直接使用单源最短路算法了。

0、要注意的就是这里并没有给出顶点的个数,只知道上限是1000,就要记录下顶点的最大的序号。

1、是无向图要记得双向的权值都是一样的。

2、用一个数组存储终点,最后遍历终点集合,找出最小的那个。

学习了一下dijkstra的优先队列优化,总结一下,用一个struct  edge来存储边的信息(包括终点,以及权值),用一个vector 来存储每个顶点指向的边的信息记为 G[ ],G[i]表示以i为起点的边的信息。用pair<int,int> 来表示一对最短距离和顶点的编号。

这个优化的重点就是用优先队列取出每次最短距离最小的点,如果当前的最小值并不是最短距离就丢弃。在遍历与这个点相连的所有点,利用已知最短距离更新其他点的当前最短距离。

优先队列的优化:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define M 1009
#define INF 0x3f3f3f3f
int t,s,d,n;
struct edge
{
    int to,w;
};
vector<edge> G[M];
typedef pair<int,int> P;//first表示距离,second 表示的是顶点的编号
int dis[M];
int ed[M];
void dijkstra()
{
    priority_queue<P,vector<P>,greater<P> > q; //使用优先队列进行优化
    fill(dis,dis+M,INF);
    dis[0] = 0;
    q.push(P(0,0));
    while(!q.empty()) //
    {
        P p = q.top(); //找到的最小距离的边
        q.pop();
        int u = p.second; //拥有最小距离的边的顶点
        if(dis[u] < p.first) continue; //如果该顶点的最小距离已经小于当前的最小距离 (取出的最小值不是最短距离就丢弃)
        for(int i = 0;i < G[u].size();i++) //取出所有与这个边相连的边 更新最小距离
        {
            edge e = G[u][i];
            if(dis[e.to] > dis[u] + e.w)
            {
                dis[e.to] = dis[u]+e.w;
                q.push(P(dis[e.to],e.to)); //往堆里插入当前最短距离和顶点的值对
            }
        }
    }
}
int main()
{
    while(scanf("%d %d %d",&t,&s,&d)==3)
    {
        memset(ed,0,sizeof(ed));
        n = 0;
        for(int i = 0;i < M;i++)
            G[i].clear();//要放在赋值之前进行初始化orzz
        for(int i = 0;i < t;i++)
        {
            int a,b,c;
            edge e;
            scanf("%d %d %d",&a,&b,&c);
            if(n<a) n = a;
            if(n<b) n = b;
            e.to = b; e.w = c;
            G[a].push_back(e);
            e.to = a;
            G[b].push_back(e); //无向图 双向的路径
        }
        n++;
        for(int i = 0;i < s;i++)
        {
            int a;
            scanf("%d",&a);
            edge e;
            e.to = a;e.w = 0;
            G[0].push_back(e); //把车站看成与起点之间存在一条权值为0的边,这样就可以轻松的使用单源最短路解决
            e.to = 0;
            G[a].push_back(e);
        }
        for(int i = 0;i < d;i++)
        {
            scanf("%d",&ed[i]);
        }
        dijkstra();
        int minn = INF;
        for(int i = 0;i < d;i++)
        {
            minn = min(minn,dis[ed[i]]);//找出最小的距离
        }
        printf("%d\n",minn);
    }
    return 0;
}

未优化的朴素写法:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 1009
#define INF 0x3f3f3f3f
int map[M][M];
int dis[M];
int vis[M];
int ed[M];
int t,s,d;
int n;
void dijkstra()
{
    for(int i = 0;i <= n;i++)
        dis[i] = map[0][i];
    dis[0] = 0;
    vis[0] = 1;
    for(int i = 1;i <= n;i++)
    {
        int min = INF;
        int k;
        for(int j = 1;j <= n;j++)  //找出离起点最近的点(花费大部分时间) 可以用优先队列进行优化
        {
            if(!vis[j] && dis[j]<min)
            {
                min = dis[j];
                k = j;
            }
        }
        if(min == INF) return ;
        vis[k] = 1;
        for(int j = 1;j <= n;j++)//利用已经找到的最近的点k更新最小距离还不确定的点当前的最小距离
        {
            if(!vis[j] && dis[j]>dis[k]+map[k][j])
                dis[j] = dis[k]+map[k][j];
        }
    }
}
int main ()
{
    while(scanf("%d %d %d",&t,&s,&d)==3)
    {
        memset(vis,0,sizeof(vis));
        for(int i = 0;i < M;i++)
            for(int j = 0;j < M;j++)
            map[i][j] = INF;
        n = -INF;
        for(int i = 0;i < t;i++)
        {
            int a,b,c;
            scanf("%d %d %d",&a,&b,&c);
            if(n<a) n = a; //找出点的个数
            if(n<b) n = b;
            if(c<map[a][b])
            map[a][b]=map[b][a]=c;//无向图
        }
        for(int i = 0;i < s;i++)
        {
            int a;
            scanf("%d",&a);
            map[0][a]=map[a][0]=0;
        }
        for(int i = 0;i < d;i++)
        {
            scanf("%d",&ed[i]);
        }
        dijkstra();
        int minn = INF;
        for(int i = 0;i < d;i++)
        {
            if(minn > dis[ed[i]])
                minn = dis[ed[i]]; //找出最小的距离
        }
        printf("%d\n",minn);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值