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(这使我经历了另外两个测试用例)。但仍然上面给出了错误的答案。我哪里错了?
答案 0 :(得分:1)
一旦弹出,从priority_queue开始,您可以保证它是最短路径,但不是当节点只是计算节点的邻居时。
目前,您在min_dist
中设置push_node
(对邻居也是如此)。
举例说明3个节点A
,B
,E
(退出):
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;
}
你只能找到一条路径,你会忽略稍后找到的较短路径,给你错误的解决方案。