最短路径 Dijkstra

最小堆优化

  • 优化的点是每次直接通过最小堆的堆顶找到最短路径最小的未搜索的点
  • 省去了一层遍历
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
int h[N], e[N], ne[N], w[N], n, m, idx = 0, d[N];
bool visited[N];
void add(int a, int b, int c){e[idx] = b; ne[idx] = h[a]; w[idx] = c; h[a] = idx++;}
int dijkstra(int s)
{
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> m_heap;
    fill(d, d + N, INF);
    d[s] = 0;
    m_heap.push({0, 1});
    while(m_heap.size())
    {
    	// 堆顶的点就是此次搜索的点
        int u = m_heap.top().second, ud = m_heap.top().first;
        m_heap.pop();
        // 这一步判断不可省
        if(visited[u])
            continue;
        visited[u] = true;
        for(int v = h[u]; v != -1; v = ne[v])
        {
            int j = e[v];
            if(visited[j] == false && ud + w[v] < d[j])
            {
                d[j] = ud + w[v];
                m_heap.push({d[j], j});
            }
        }
    }
    return d[n] == INF ? -1 : d[n];
}

邻接矩阵版

const int N = 510, INF = 0x3f3f3f3f;
int G[N][N], d[N], n, m, a, b, c;
bool visited[N];
int Dijkstra(int s)
{
    // fill(d, d + N, INF);		// 初始化到各点的最短距离
    memset(d, 0x3f, sizeof d);
    d[s] = 0;					// s为出发点
    for(int i = 1; i <= n; ++i)
    {
        int u = -1;				// 寻找此时已更新的最短距离最小的点
        for(int j = 1; j <= n; ++j)
            if(visited[j] == false && (u == -1 || d[j] < d[u]))
                u = j;
        visited[u] = true;		// 更新u所能到达的点的最短距离
        for(int v = 1; v <= n; ++v)
            if(visited[v] == false && G[u][v] != INF && G[u][v] + d[u] < d[v])
                d[v] = d[u] + G[u][v];
    }							// d[n]为INF则不存在最短路径,无法到达
    return d[n] == INF ? -1 : d[n];
}
int main()
{
    cin >> n >> m;
    fill(G[0], G[0] + N * N, INF);
    // memset(G, 0x3f, sizeof(G));
    while(m--)
    {
        cin >> a >> b >> c;	
        G[a][b] = min(G[a][b], c); // 可能存在的重边,取权值最小的边
    }
    cout << Dijkstra(1);
    return 0;    
}

邻接表版

const int N = 1e5 + 10, INF = 0x3f3f3f3f;
int h[N], e[N], ne[N], w[N], n, m, idx = 0, d[N];
bool visited[N];
void add(int a, int b, int c)
{
    e[idx] = b; ne[idx] = h[a]; w[idx] = c; h[a] = idx++;
}
int Dijkstra(int s)
{
    fill(d, d + N, INF);	// 初始化到各点的最短距离
    d[s] = 0;
    for(int i = 1; i <= n; ++i)
    {
        int u = -1;			// 寻找此时已更新的最短距离最小的点
        for(int j = 1; j <= n; ++j)
            if(visited[j] == false && (u == -1 || d[j] < d[u]))
                u = j;
                
        visited[u] = true;	// 更新u所能到达的点的最短距离
        for(int v = h[u]; v != -1; v = ne[v])
        {
            int j = e[v];
            if(visited[j] == false && w[v] + d[u] < d[j])
                d[j] = w[v] + d[u];
        }
    }					    // d[n]为INF则不存在最短路径,无法到达
    return d[n] == INF ? -1 : d[n];
}

int main()
{
    fill(h, h + N, -1);
    cin >> n >> m;
    for(int i = 0; i < m; ++i)
    {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c);
    }
    cout << Dijkstra(1);
    return 0;    
}

PAT 1003 Emergency

  • 注意这里是无向图
  • 并且是多条路径、多点权的情况(一般都直接另加数组,配合条件判断使用)
const int N = 1e6, INF = 0x3f3f3f3f;
int h[N], e[N], ne[N], w[N], rt[N], d[N], num[N], tnum[N], n, m, c1, c2, idx = 0;
bool visited[N];
void add(int a, int b, int c){
    e[idx] = b; ne[idx] = h[a]; w[idx] = c; h[a] = idx++;}
void Dijkstra(int start, int end)
{
    fill(d, d + N, INF);
    fill(num, num + N, 0);
    fill(tnum, tnum + N, 0);
    d[start] = 0;
    num[start] = 1;                    // 路径数在起点处初始化为1
    tnum[start] = rt[start];           // 初始化起点处的队伍数
    for(int i = 0; i < n; ++i)
    {
        int u = -1;
        for(int j = 0; j < n; ++j)
            if(visited[j] == false && (u == -1 || d[j] < d[u]))
                u = j;
        if(u == -1) return ;
        visited[u] = true;

        for(int v = h[u]; v != -1; v = ne[v])
        {
            int j = e[v];
            if(visited[j] == false)
            {
                if(d[u] + w[v] < d[j])                // 更新最短路径情况
                {
                    d[j] = d[u] + w[v];
                    num[j] = num[u];
                    tnum[j] = rt[j] + tnum[u];
                }
                else if(d[u] + w[v] == d[j])         // 多条路径情况
                {
                    num[j] += num[u];                // 累加路径数
                    if(tnum[u] + rt[j] > tnum[j])    // 距离相同情况,取最多队伍数
                        tnum[j] = rt[j] + tnum[u];
                }
            }
        }
    }
}

int main()
{    
    fill(h, h + N, -1);
    cin >> n >> m >> c1 >> c2;
    for(int i = 0; i < n; ++i)
        cin >> rt[i];
    for(int i = 0; i < m; ++i)
    {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c);            // 注意是无向图
        add(b, a, c);
    }
    Dijkstra(c1, c2);
    cout << num[c2] << " " << tnum[c2] << endl;
    return 0;
}

PAT 1030 Travel Plan

const int N = 1e3, INF = 0x3f3f3f3f;
int h[N], e[N], ne[N], w1[N], w2[N], n, m, mstart, mend, idx = 0;
int d[N], c[N];
bool visited[N];
int pre[N];
void add(int a, int b, int c, int d){
    e[idx] = b; ne[idx] = h[a]; w1[idx] = c; w2[idx] = d; h[a] = idx++;}

void Dijkstra(int s)
{
    fill(d, d + N, INF); fill(c, c + N, INF); d[s] = 0; c[s] = 0;
    for(int i = 0; i < n; ++i)
    {
        int u = -1;
        for(int j = 0; j < n; ++j)
            if(visited[j] == false && (n == -1 || d[j] < d[u]))
                u = j;
        visited[u] = true;
        for(int v = h[u]; v != -1; v = ne[v])
        {
            int j = e[v];
            if(visited[j] == false)
            {
                if(w1[v] + d[u] < d[j]) 		// 第一标尺
                {
                    d[j] = w1[v] + d[u];
                    c[j] = w2[v] + c[u];
                    pre[j] = u;
                }
                else if(w1[v] + d[u] == d[j]) 	
                {
                    if(w2[v] + c[u] < c[j])		// 第二标尺
                    {
                        c[j] = w2[v] + c[u];
                        pre[j] = u;
                    }
                }
            }
        }
    }
}
void DFS(vector<int> &ret, int cur)
{
    if(cur == mstart)
    {
        ret.push_back(cur);
        return;
    }
    DFS(ret, pre[cur]);
    ret.push_back(cur);
}
int main()
{
    fill(h, h + N, -1);
    cin >> n >> m >> mstart >> mend;
    while(m--)
    {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        add(a, b, c, d);
        add(b, a, c, d);
    }
    Dijkstra(mstart);
    vector<int> ret;
    DFS(ret, mend);
    for(auto a : ret)
        cout << a << " ";
    cout << d[mend] << " " << c[mend];
    return 0;
}



// 邻接矩阵
int G[N][N], C[N][N];
void Dijkstra(int s)
{
    fill(d, d + N, INF); fill(c, c + N, INF); d[s] = 0; c[s] = 0;
    for(int i = 0; i < n; ++i)
    {
        int u = -1;
        for(int j = 0; j < n; ++j)
            if(visited[j] == false && (n == -1 || d[j] < d[u]))
                u = j;
        visited[u] = true;

        for(int v = 0; v < n; ++v)
        {
            if(visited[v] == false && G[u][v] != INF)
            {
                if(d[u] + G[u][v] < d[v])
                {
                    d[v] = d[u] + G[u][v];
                    c[v] = c[u] + C[u][v];
                    pre[v] = u;
                }
                else if(d[u] + G[u][v] == d[v])
                {
                    if(c[u] + C[u][v] < c[v])
                    {
                        c[v] = c[u] + C[u][v];
                        pre[v] = u;
                    }
                }
            }
        }

    }
}
int main()
{
    memset(G, 0x3f, sizeof(G));
    memset(C, 0x3f, sizeof(C));
    cin >> n >> m >> mstart >> mend;
    while(m--)
    {
        int a, b;
        cin >> a >> b;
        cin >> G[a][b] >> C[a][b];
        G[b][a] = G[a][b]; C[b][a] = C[a][b];
    }
    Dijkstra(mstart);
    DFS(mend);
    cout << d[mend] << " " << c[mend];
    return 0;
}
  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值