( 图论专题 )【 最短路 】
dijkstra的堆优化(最简版本)
先了解不用堆优化的dijkstra:https://blog.csdn.net/weixin_43828245/article/details/90722389
推荐视频讲解(代码是Python写的,重点听思路):https://www.bilibili.com/video/av25829980
了解c++优先队列:https://blog.csdn.net/weixin_43828245/article/details/90742490
前向星写的dijkstra
此代码用于稀疏图,或者节点数很多二维数组存不下。在稠密图中可以继续使用邻接矩阵。
#include <iostream>
#include <stdio.h>
#include <queue>
#include <cstring>
#define inf 0x3f3f3f
using namespace std;
typedef struct node { // 定义优先队列
int v,date;
} ty;
bool operator < ( const ty &a, const ty &b ) // 定义优先队列
{
return a.date>b.date;
}
struct edge { // 存邻接表的边
int to,w,next;
} a[100005];
int head[105];
int dis[105];
int via[105];
int cnt;
int n,m;
ty t,d;
void dijkstra( int v0 ) // 堆优化的dijkstra + 邻接表
{
priority_queue <ty> Q;
memset(dis,inf,sizeof(dis));
dis[v0] = 0;
t.v = v0;
t.date = 0;
Q.push(t);
while ( !Q.empty() ) {
if ( via[Q.top().v]==1 ) {
Q.pop();
continue ;
}
t = Q.top();
Q.pop();
int u = t.v;
dis[u] = t.date;
via[u] = 1;
for ( int i=head[u]; i!=-1; i=a[i].next ) { // 这块代码容易出错,好好看
int j = a[i].to; // 通过邻接表直接找相邻的点
if ( via[j]==0 && dis[j]>dis[u]+a[i].w ) {
dis[j] = dis[u]+a[i].w;
d.v = j;
d.date = dis[j];
Q.push(d);
}
}
}
cout << dis[n] << endl;
}
int main()
{
while ( cin >> n >> m ) {
cnt = 0;
memset(head,-1,sizeof(head));
memset(via,0,sizeof(via));
for ( int i=0; i<m; i++ ) {
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
a[cnt].to = y; // 无向图
a[cnt].w = z;
a[cnt].next = head[x];
head[x] = cnt++;
a[cnt].to = x; // 正反存两次
a[cnt].w = z;
a[cnt].next = head[y];
head[y] = cnt ++;
}
dijkstra(1);
}
return 0;
}
F - Wormholes(SPFA+邻接表)
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e5+10;
int head[maxn];
int dis[maxn];
int via[maxn];
int num[maxn];
int cnt,n,m,mm;
struct node {
int to,w,next;
} e[maxn];
void addage( int u, int v, int w )
{
e[cnt].to = v;
e[cnt].w = w;
e[cnt].next = head[u];
head[u] = cnt++;
}
int spfa( int node )
{
memset(num,0,sizeof(num));
memset(via,0,sizeof(via));
memset(dis,inf,sizeof(dis)); // 最短路设成inf,最长路设成0
queue <int> Q;
dis[node] = 0; via[node] = 1;
int tot = 0;
Q.push(node);// 把根节点push进去
while ( !Q.empty() ) {
int u = Q.front(); Q.pop();// pop要两个一起
via[u] = 0; // 取消标记,这个容易遗漏,(进队列标记为1,出队列取消标记)
for ( int i=head[u]; i!=-1; i=e[i].next ) {
int y = e[i].to, w = e[i].w;
if ( dis[y]>dis[u]+w ) { // 满足松弛条件。
dis[y] = dis[u] + w;
if ( via[y]==0 ) { // 更新完了,如果没标记再push这个点进去
if ( ++num[y]>n ) return 0; // 有负权回路
via[y] = 1;
Q.push(y);
}
}
}
}
return 1;
}
int main()
{
int listt,i,j,x,y,z;
cin >> listt;
while ( listt-- ) {
cin >> n >> m >> mm;
memset(head,-1,sizeof(head));
cnt = 0;
for ( i=0; i<m; i++ ) {
cin >> x >> y >> z;
addage(x,y,z);
addage(y,x,z);
}
for ( i=0; i<mm; i++ ) {
cin >> x >> y >> z;
addage(x,y,-z);
}
if ( spfa(1)==0 ) {
cout << "YES" << endl;
}
else {
cout << "NO" << endl;
}
}
return 0;
}