【模板】Dijkstra迪杰特斯拉算法
邻接矩阵+朴素版dijkstra->稠密图使用
邻接表+堆优化版dijkstra->稀疏图使用
判断方法:以m=nlogn为界,m越大,图越稠密(参考快速判断一个图是稀疏图的还是稠密图_稠密图和稀疏图界定-CSDN博客)
不同类型的图的存储 邻接表 模板
//无权图
int n, m;
vector<vector<int> > adj;
void solve() {
int a, b;
cin >> n >> m;
adj.resize(n + 1);
for (int i = 0; i < m; ++i) { //建图
cin>>a>>b;
adj[a].push_back(b);
adj[b].push_back(a);//无向图时用
}
return;
}
//带权图
int n, m;
vector<vector<pii>> adj; // 有权图 {节点, 边权}
void solve()
{
int a, b, c;
cin>>n>>m;
adj.resize(n+1); //初始化邻接表
for (int i = 0; i < m; ++i) { //建图
cin>>a>>b>>c;
adj[a].push_back(make_pair(b, c));
adj[b].push_back(make_pair(a, c));//无向图时用
}
return;
}
算法运用:
main():测试样例数目
solve():题解
其他详见注释
/*
*邻接表
*堆优化版dijkstra(稀疏图时好)
*时间复杂度 O(mlogn)
*/
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
/*—全局的邻接表所需变量--函数----——————————————————————————————————————————————————————————*/
void display_route(int s, int f, vector<int>&pre, vector<int>&path); // 展示最短路径
int n, m; // 节点数,边数
vector<vector<pii>> adj; // 有向有权图 邻接表
/*———dijkstra——————————————————————————————————————————————————————————————————————————*/
/*
*[pre path] 在需要存路径时使用
*[dis vis] 根据需要可选择设为局部变量并传参(是否有多个起点什么的)选择放局部变量还是全局变量
*若n m未知,则可以用adj.size()或其他什么的size()求得。但此种情况建图时的写法也会不同。
*/
// 求start号点到其他点的最短距离,如果不存在,则(dis[n] == 0x3f3f3f3f)
void dijkstra(int start, vector<int>& dis, vector<int>& pre){
dis.resize(n+1, INF);
pre.resize(n+1, -1); //要存路径时用
vector<int> vis(n+1, 0);
dis[start] = 0;
priority_queue<pii, vector<pii>, greater<pii>> pq; // 小根堆,存储节点编号和距离
pq.push(make_pair(start, 0)); // first存储节点编号,second存储距离
while (!pq.empty()) {
pii p = pq.top();
pq.pop();
int u = p.first, d = p.second;
if(vis[u]) continue;
vis[u]=1;
for (int i = 0; i < adj[u].size(); i++) {
int v = adj[u][i].first, w = adj[u][i].second;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
pq.push(make_pair(v, dis[v]));
pre[v] = u; // 要存路径时用
}
}
}
return;
}
void solve(){
int a, b, c;
cin>>n>>m;
adj.resize(n+1); //初始化邻接表
for(int i=0;i<m;i++){ //建图
cin>>a>>b>>c;
adj[a].push_back(make_pair(b, c));
adj[b].push_back(make_pair(a, c));//无向图时用
}
//运行算法
//如果dis只用一次的话,干脆在dijkstra里面,免得传来传去
vector<int> dis, pre; //pre在要存路径时才用
dijkstra(1, dis, pre); //1为起点
//输出路径
vector<int> path;
int s, f;//起点,终点
cin>>s>>f;
cout<<"dis: "<<dis[f]<<endl;
display_route(s, f, pre, path);
return;
}
void display_route(int s, int f, vector<int>&pre, vector<int>&path)
{
cout<<"path: ";
for(int i=f; i!=-1; i=pre[i]){
// cout<<i<<" "; // 这样的话是倒序的
path.push_back(i); // 先倒序存起来
}
for(int i=path.size()-1;i>=0;i--){
cout<<path[i]<<" ";
}
cout<<endl;
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T=1;
// cin>>T;
while (T--) solve();
return 0;
}
/*
*邻接矩阵(优势在于判断是否有边)
*朴素dijkstra算法(稠密图时好)
*时间复杂是 O(n2+m), n 表示点数,m 表示边数
*/
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
/*—建立邻接矩阵——————————————————————————————————————————————————————————————————————————*/
#define N 100
void CreateUDN(int n, int m); // 建立邻接矩阵
void dijkstra(int s);// s为起始点
// void display_route(int s, int f);// 展示最短路径
int arcs[N][N];//邻接矩阵,权重为整数
int n, m; // 定点数,边数
// vector<vector<int> > arcs(N, vector<int>(N)); // 用vec也行
// char vex[N]; //顶点表,在顶点为字母时可能会用
// int cost[N][N];// 如果还有额外开销则再加一个矩阵
// 有权w,0(i==j), INF
// 无权把w删掉1,0(i==j或无边)
vector<int> rout[N];
void CreateUDN(int n, int m)
{
int u, v, w;
memset(arcs, INF, sizeof(arcs));
for(int i=0;i<m;i++){
cin>>u>>v>>w;
arcs[u][v]=w;
arcs[v][u]=w; //无向图使用
}
return;
}
/*———dijkstra——————————————————————————————————————————————————————————————————————————*/
int dis[N], vis[N];// 距离,是否访问
void dijkstra(int s){
memset(dis, INF, sizeof(dis));
memset(vis, 0, sizeof(vis));
for(int i=1;i<=n;i++){
dis[i]=arcs[s][i];
}
dis[s] = 0;
vis[s]= 1 ;
for(int i=1;i<=n;i++){
rout[i].push_back(s);
}
for (int i = 1; i <= n; i++){
int u = 0, mind = 0x3f3f3f3f;
for (int j = 1; j <= n; j++){
if (!vis[j] && dis[j] < mind)
u = j, mind = dis[j];
}
vis[u] = 1;
rout[u].push_back(u);
// for (auto ed : e[u]) {
// int v = ed.v, w = ed.w;
// if (dis[v] > dis[u] + w) dis[v] = dis[u] + w;
// }
for(int j=1;j<=n;j++){
/*不用存路径的做法*/
// dis[j] = min(dis[j], dis[u] + arcs[u][j]);
/*要存的*/
if (!vis[j] && dis[j]>dis[u]+arcs[u][j]){
dis[j]=dis[u]+arcs[u][j];
rout[j]=rout[u];
}
}
}
return;
}
void display_route(int s, int f)
{
cout<<"path: ";
for(int i=0;i<rout[f].size();i++){
cout<<rout[f][i]<<" ";
}
cout<<endl;
return;
}
void solve(){
int a, b, c;
cin>>n>>m;
CreateUDN(n, m); //初始化邻接矩阵
//运行算法
dijkstra(1); //0为起点
//输出路径
int s, f;//起点,终点
cin>>s>>f;
cout<<"dis:"<<dis[f]<<endl;
display_route(s, f);
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T=1;
// cin>>T;
while (T--) solve();
return 0;
}
示例数据:
输入
6 9
1 2 7
1 3 9
1 6 14
2 3 10
2 4 15
3 4 11
3 6 2
4 5 6
5 6 9
1 5
输出
dis: 20
path: 1 3 6 5
参考: