稠密图用邻接矩阵存储,稀疏图用邻接表存储
邻接表存储图的方式
int h[N];// 存储点,h[a]表示点a指向的一条边
int e[N];// 存储边,e[idx]表示边idx指向的点
int ne[N];// 存储边,e[idx]表示和边idx同起点边
int w[N];// 存储权重,w[idx]表示边idx的权重
int idx;// 边的编号
void add(int a, int b, int c){
e[idx] = b;// idx表示又新增了一条边(结合idx++来看),e[idx]表示这条边指向点b
ne[idx] = h[a];// 和新增边idx同起点的边,也就是起点同为a的边,h[a]赋值给ne[idx]
w[idx] = c;// 新增边的权重是c
h[a] = idx++;// 链表的头节点指向新增边idx
}
朴素版Dijkstra
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<string>
#include<set>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int N=1e3+5;
int n,m;
int g[N][N];// 邻接矩阵存储图
int dis[N];// 表示各个点到源点的距离,dijkstra就是将此数组更新n-1次
bool st[N];
int dijkstra(){
dis[1]=0;
for(int i=0;i<n-1;i++){
int t=-1;
for(int j=1;j<=n;j++)
if(!st[j]&&(t==-1||dis[t]>dis[j]))
t=j;
for(int j=1;j<=n;j++)
dis[j]=min(dis[j],dis[t]+g[t][j]);
// dis[j]:源点直接到点j的距离
// dis[t]+g[t][j]:源点先到点t,再从t到点j的距离
st[t]=true;
}
return dis[n];
}
int main(void){
while(~scanf("%d%d",&n,&m)&&n!=0&&m!=0){
memset(dis,INF,sizeof dis);
memset(g,INF,sizeof g);
memset(st,false,sizeof st);
for(int i=0;i<m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
g[a][b]=g[b][a]=min(g[a][b],min(g[a][b],c));
}
printf("%d\n",dijkstra());
}
return 0;
}
/*
* When ability does not derserve ambition, just keep moving
*/
堆优化版Dijkstra
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<string>
#include<set>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int N=2e5+5;
typedef pair<int,int> PII;
int n, m;
int h[N],e[N],ne[N],w[N],idx;
int dis[N];
bool st[N];
void add(int a,int b,int c){
e[idx]=b;
ne[idx]=h[a];
w[idx]=c;
h[a]=idx++;
}
int dijkstra(){
memset(dis,INF,sizeof dis);
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0,1});
while(heap.size()){
auto t=heap.top();
heap.pop();
int v=t.second,dist=t.first;
if(st[v])
continue;
st[v]=true;
for(int i=h[v];i!=-1;i=ne[i]){
int j=e[i];
if(dis[j]>w[i]+dist){
dis[j]=w[i]+dist;
heap.push({dis[j],j});
}
}
}
if(dis[n]==INF)
return -1;
return dis[n];
}
int main(void){
scanf("%d%d",&n,&m);
memset(h,-1,sizeof h);
while(m--){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
cout<<dijkstra()<<endl;
return 0;
}
/*
* When ability does not derserve ambition, just keep moving
*/
Bellman_Ford
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<string>
#include<set>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 500 + 5;
const int M = 1e4 + 10;
int n, m, k;
int dis[N], backup[N];
struct Edge {
int a, b, w;
} edge[M];
int bellman_ford() {
memset(dis, INF, sizeof dis);
dis[1] = 0;
for (int i = 0; i < k; i++) {
memcpy(backup, dis, sizeof dis);
// memcpy操作可以根据样例
// 4 4 1
// 1 2 1
// 2 3 1
// 3 4 1
// 1 3 -2
// 得出原因,主要是有边数限制
// 如果不使用上一次的更新结果,那么可能第一次更新便可能根据遍历顺序,直接走到终点
// 但是这样就超出边数限制了,所以不可取
for (int j = 0; j < m; j++) {
int a = edge[j].a;
int b = edge[j].b;
int w = edge[j].w;
dis[b] = min(dis[b], backup[a] + w);
}
}
return dis[n];
}
int main(void) {
scanf("%d%d%d", &n, &m, &k);
for (int i = 0; i < m; i++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
edge[i] = {a, b, c};
}
int t = bellman_ford();
if (t > INF / 2)
puts("impossible");
else
printf("%d\n", t);
return 0;
}
/*
* When ability does not derserve ambition, just keep moving
*/
SPFA
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<string>
#include<set>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 5;
int n, m;
int dis[N];
bool st[N];
int h[N], e[N], ne[N], w[N], idx;
void add(int a, int b, int c) {
e[idx] = b;
ne[idx] = h[a];
w[idx] = c;
h[a] = idx++;
}
int spfa() {
memset(dis, INF, sizeof dis);
dis[1] = 0;
queue<int> q;
q.push(1);
st[1] = true;
while (q.size()) {
int t = q.front();
q.pop();
st[t] = false;
for (int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];
if (dis[j] > dis[t] + w[i]) {
dis[j] = dis[t] + w[i];
if (!st[j]) {
q.push(j);
st[j] = true;
}
}
}
}
return dis[n];
}
int main(void) {
memset(h, -1, sizeof h);
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
}
int ans = spfa();
if (ans > INF / 2)
puts("impossible");
else
printf("%d\n", ans);
return 0;
}
/*
* When ability does not derserve ambition, just keep moving
*/
Floyd
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<string>
#include<set>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int N=1e3+5;
int n,m;
int dis[N][N];
bool st[N];
int floyd(){
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
return dis[1][n];
}
void init() {
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (i == j)
dis[i][j] = 0;
else
dis[i][j] = INF;
}
int main(void){
while(~scanf("%d%d",&n,&m)&&n!=0&&m!=0){
init();
memset(dis,INF,sizeof dis);
for(int i=0;i<m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
dis[a][b]=dis[b][a]=min(dis[a][b],min(dis[a][b],c));
}
printf("%d\n",floyd());
}
return 0;
}
/*
* When ability does not derserve ambition, just keep moving
*/