堆优化的Dijkstra找最短路超时
原题链接:https://www.acwing.com/problem/content/1477/?%ra=link
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=510,M=610;
int h[N],e[M],ne[M],w[M],idx;
int n,m,start,last; // 起点start,终点last
int ways[N],max_p[N]; // 每个城市的最短路条数,沿最短路能集结的最大人数
int p[N],dist[N]; // 每个城市的人数,到起点的距离
bool st[N]; // 标记该点是否移出点集(是否用过)
typedef pair<int,int>PII;
#define x first
#define y second
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dijkstra()
{
memset(dist,0x3f,sizeof dist); // 距离初始化为正无穷
dist[start]=0;ways[start]=1;max_p[start]=p[start]; // 起点到起点的距离为0,路径默认为1,沿着最短路可以汇集的最大人数为城市原有人数
priority_queue<PII,vector<PII>,greater<PII>>heap; // 定义小根堆
heap.push({0,start}); // 起点距离,编号入堆
while(heap.size())
{
auto t=heap.top(); // 取出堆顶元素
heap.pop();
int ver=t.y,distance=t.x; // 取出结点编号和到起点的距离
if(st[ver])continue; // 如果先前已被遍历,执行下一次循环
st[ver]=true;
for(int i=h[ver];~i;i=ne[i]) // 利用该点枚举每条出边
{
int j=e[i];
if(dist[j]>distance+w[i]) // 找到更短的路径
{
ways[j]=ways[ver]; // 到该结点的最短路径有ways[ver]条
max_p[j]=max_p[ver]+p[j];
dist[j]=distance+w[i]; // 更新距离
heap.push({dist[j],j}); // 入堆
}
else if(dist[j]==distance+w[i]) // 路径长度相同
{
ways[j]+=ways[ver]; // 路径条数增加
max_p[j]=max(max_p[j],max_p[ver]+p[j]); // 人数取较大者
}
}
}
}
int main()
{
memset(h,-1,sizeof h);
scanf("%d%d%d%d",&n,&m,&start,&last);
for(int i=0;i<n;i++) // 读入每个城市原有人数
scanf("%d",&p[i]);
for(int i=0;i<m;i++) // 读入无向边的信息
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);add(y,x,z);
}
dijkstra(); // 最短路径查询
cout<<ways[last]<<' '<<max_p[last]<<endl;
return 0;
}
运行结果及报错内容
TLE