文章目录
前言
今天 wa了半天 经队友提醒 遗漏了处理无向图时 在链式前向星中 推入双向弧 故记录一下以免忘记
一、构建链式前向星
普通邻接矩阵在处理达到1e5数量级点时会爆空间 而且在对于稀疏图时空间浪费较大 可以采用 v e c t o r vector vector 动态数组构建但也会因存在大量孤立点导致空间浪费 而个人对于链表构建 指针操作不是很掌握而且也不适应 故采用链式前向星这种利用数组模拟邻接链表的方式 该结构只与边的数量有关 而且在查询时因只遍历存在边 故时间上也有优化 亦解决了稀疏图空间浪费的问题
二、堆优化 d i j k s t r a dijkstra dijkstra
朴素 d i j k s t r a dijkstra dijkstra 算法因需遍历所有边易超时 故使用优先队列采用小顶堆来快速查询当前最小边
例题
1624: 最短路
Time Limit: 1 Sec Memory Limit: 128 MB
Description
有n个城市编号为1—n,m条路,告诉你每条路的长度,求给定两点的最短路径长度。
Input
T 组数据
每组数据第一行有两个正整数n,m(n<=1000,m<=10000)分别表示城市的数量和路的条数,接下来m行,每行3个整数a,b,c,表示城市a和城市b之间有一条c长度的路
最后一行输入两个整数x,y。
Output
输出城市 x 到城市 y 的最短路径。如果不存在输出-1。
Sample Input
2
3 2
1 2 2
2 3 3
1 3
4 2
1 2 3
1 3 2
1 4
Sample Output
5
-1
AC代码
#include<bits/stdc++.h>
using namespace std;
int t,n,m;
struct mp
{
int to,vl,next;
}edge[20003];//因需构建双向边 故需开2*m的边
struct node
{
int id,ds;
friend bool operator <(node a,node b){return a.ds>b.ds;}
//重载运算符,构建小顶堆
};
priority_queue<node> q;
int head[1003],dis[1003],vis[1003];
int main()
{
scanf("%d",&t);
int u,v,d;
while(t--)
{
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;++i)dis[i]=2147483647;
while(!q.empty())
{
q.pop();
}
for(int i=1;i<=2*m;i+=2)
{
scanf("%d%d%d",&u,&v,&d);
edge[i].to=v;
edge[i].vl=d;
edge[i].next=head[u];
head[u]=i;
edge[i+1].to=u;
edge[i+1].vl=d;
edge[i+1].next=head[v];
head[v]=i+1;//推入双向边
}
int s,t;
scanf("%d%d",&s,&t);
dis[s]=0;
node p;
p.id=s;
p.ds=0;
q.push(p);
while(!q.empty())
{
node a=q.top();
q.pop();
int now=a.id;
if(vis[now]==1)continue;
vis[now]=1;
for(int i=head[now];~i;i=edge[i].next)
{
int j=edge[i].to;
if(dis[now]+edge[i].vl<dis[j])
{
dis[j]=dis[now]+edge[i].vl;
p.id=j;
p.ds=dis[j];
q.push(p);
//不用更新原优先队列 因是小顶堆 最小权边始终在队顶
}
}
}
dis[t]==2147483647?puts("-1"):printf("%d\n",dis[t]);
}
return 0;
}
该题数据范围小 故临界链表和朴素dijkstra也能过