Dijkstra的算法实现:小鼠和迷宫

时间:2014-08-02 04:50:38

标签: c++ algorithm dijkstra

This是一个涉及Dijkstra算法的简单问题,用于找到以给定顶点为根的最短距离树。以下是被接受的代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<deque>
#include<queue>
#include<utility>
#include<vector>
#include<climits>
#include<algorithm>
#include<stack>
using namespace std;
bool debug=false;
typedef long long int lld;
typedef unsigned long long int llu;
struct compare_vertex{
    bool operator()(const pair<int,lld> &p1 , const pair<int,lld> p2){
        return p1.second<p2.second;
    }
};
typedef priority_queue<pair<int,lld> , vector<pair<int,lld> > , compare_vertex> node_pq;
class Solver{
    int n , e , t , m;
    vector<deque<pair<int,lld> > > adjList;
    vector<lld> min_dist;
    node_pq pq;
    void push_node(int index , lld dist){
        if(min_dist[index] < dist){
            return;
        }
        pq.push(make_pair(index , dist));
        min_dist[index] = dist;
    }
public:
    Solver(){
        scanf("%d",&n);
        adjList = vector<deque<pair<int,lld> > >(n);
        min_dist= vector<lld>(n , INT_MAX);

        scanf("%d",&e);
        --e;
        scanf("%d",&t);
        scanf("%d",&m);

        int x , y ;
        lld z;
        for(int i=0;i<m;++i){
            scanf("%d %d %lld",&x , &y , &z);
            --x;--y;
            adjList[y].push_back(make_pair(x , z));
        }
    }
    int solve(){
        push_node(e , 0);

        int size;
        pair<int,lld> vertex;
        while(!pq.empty()){
            vertex = pq.top();
            pq.pop();

            size = adjList[vertex.first].size();
            for(int i=0;i<size;++i){
                push_node(adjList[vertex.first][i].first , vertex.second +   adjList[vertex.first][i].second);
            }
        }

        int count = 0;
        for(int i=0;i<n;++i){
            count += min_dist[i]<=t ? 1 : 0;
        }

        return count;
    }
};
int main(int argc , char **argv)
{
    if(argc>1 && strcmp(argv[1],"DEBUG")==0) debug=true;
    Solver s;
    printf("%d\n",s.solve());
    return 0;
}

算法很贪婪,所以我们逐步选择最接近树的顶点。这意味着,一旦选择了顶点,就不会有来自根的任何较短路径。因此,重新访问顶点以查看当前距离是否短于先前距离是徒劳的(这是我们在Bellman-Ford算法中所做的事情)。因此,push_node函数中的返回条件应为:

if(min_dist[index] != INT_MAX){
    return; 
}

但这给出了错误答案。最初我认为int数据类型可能有溢出,所以我将所有距离变量更改为long long int(这使我经历了另外两个测试用例)。但仍然上面给出了错误的答案。我哪里错了?

2 个答案:

答案 0 :(得分:1)

一旦弹出,从priority_queue开始,您可以保证它是最短路径,但不是当节点只是计算节点的邻居时。

目前,您在min_dist中设置push_node(对邻居也是如此)。

举例说明3个节点ABE(退出):

E <- A 4
E <- B 1
B <- A 1

您从E开始,然后是push_node(A, 4)push_node(B, 1) 所以你设置了所有min_dist

当您弹出B时,您使用较低的值更正min_dist(A)

除了您当前的解决方案之外,您可以在弹出时检查是否未设置min_dist,然后设置min_dist并从此节点传播。

答案 1 :(得分:1)

只要顶点没有从优先级队列中弹出,即只要它不是距离根最近的未完成顶点,您仍然可以找到更短的路径。如果你这样做

if(min_dist[index] != INT_MAX){
    return; 
}

你只能找到一条路径,你会忽略稍后找到的较短路径,给你错误的解决方案。