#include <stdio.h>
#include <string.h>
#include <vector>
#include <queue>
#include <iostream>
using namespace std;
const int MAXV = 1000;
const int INF = 1000000000;
struct Node
{
int v,dis;
};
vector<Node> Adj[MAXV];
int n;//n为顶点数,图G使用邻接表实现,MAXV为最大顶点数(点数决定如何遍历边)
int m;// 边数(决定输入什么样的图)
int s;//起点
int d[MAXV];//起点到达各个点的最短路径长度
bool vis[MAXV] = {false};//标记数组,vis[i]==true表示已访问,初值均为false
int pre[MAXV]={0}; //记录到某一个点的前驱
void Dijkstra(int s)
{
fill(d,d+MAXV,INF);
d[s] = 0;//起点s到达自身的距离为0
//遍历所有的点
for(int i=0;i<n;i++)
{
//u为使得d[u]最小的点,MIN存放该最小的d[u]
int u = -1,MIN = INF;
//每一趟找一个已连通的最短路径的点出来
for(int j=0;j<n;j++)
{
if(vis[j] == false && d[j] < MIN)
{
u = j;
MIN = d[j];
}
}
//找不到小于INF的d[u],说明剩下的顶点和起点s不连通
if(u == -1)
{
return;
}
//找到了
else
{
vis[u] = true;//找到则标记成已访问,每一趟可以确定一个最短点
//遍历u能到达的所有顶点v,并判断以u为中转到j的距离是否比原来的小,如果小则更新
for(int j=0;j < Adj[u].size();j++)
{
int v = Adj[u][j].v;
//以当前最短路径的点为中转,看看是否比原来的距离小 ,如果小,则优化d[v]
if(vis[v] == false && d[u] + Adj[u][j].dis < d[v])
{
d[v] = d[u] + Adj[u][j].dis;
//记录前驱
pre[v] = u;
}
}
}
}
}
//输出从起点到v的最短路径
void print(int s,int v)
{
if(v == s)
{
cout << s << endl;
return;
}
print(s,pre[v]);
cout<< v << endl;
}
int main()
{
//顶点个数,边数,起点编号
cin >> n >> m >> s;
int u,v,w;
Node tmp;
for (int i=0;i<m;i++)
{
cin >> u >> v >> w;
tmp.v = v;
tmp.dis = w;
Adj[u].push_back(tmp);
}
Dijkstra(s);
for(int i=0;i<n;i++)
{
cout << d[i] << " ";
}
cout << endl;
print(0,5);
return 0;
}
练习: PAT A1003 Emergency
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXV = 510;
const int INF = 1000000000;
//n为点数,m为边数,st和ed分别为起点和终点
//G为邻接矩阵,weight为点权
//d[]记录最短距离,w[]记录最大点权之和
int n,m,st,ed,G[MAXV][MAXV],weight[MAXV];
int d[MAXV],w[MAXV];
//vis[i] == true 表示顶点i已访问
bool vis[MAXV] = {false};
vector<int> pre[MAXV];
void Dijkstra(int s)
{
fill(d,d+MAXV,INF);
d[s] = 0;
//每次找出一个最短的点,一共找n个 ,最短的点就是在最短路径中的点,设置为访问
for(int i=0;i<n;i++)
{
int u = -1,MIN = INF;
//找最短的点
for(int j=0;j<n;j++)
{
if(vis[j] == false && d[j] < MIN)
{
u = j;
MIN = d[j];
}
}
if(u == -1 ) return;
vis[u] = true;
//看u能到哪些点 ,并以u为中转,更新其他距离
//以u为中转,到v
for(int v=0;v<n;v++)
{
if(vis[v] == false && G[u][v] != INF)
{
if(d[u] + G[u][v] < d[v])
{
d[v] = d[u] + G[u][v];
pre[v].clear();
//令v的前驱为u
pre[v].push_back(u);
}
else if(d[u]+G[u][v] == d[v])
{
pre[v].push_back(u);
}
}
}
}
}
//求最大值
int optvalue = -INF;
//最优路径及临时路径
vector<int> path,tempPath;
//路径数+1
int totalCount = 0;
void DFS(int v)
{
// cout << endl;
//到达叶子节点,即起点
if(v == st)
{
totalCount++;
tempPath.push_back(v);
int value = 0;
for(int i=0;i<tempPath.size();i++)
{
// value = value + G[ tempPath[i] ][ tempPath[i+1] ];
value = value + weight[tempPath[i]];
}
if(value > optvalue)
{
optvalue = value;
path = tempPath;
}
//回溯
tempPath.pop_back();
return;
}
//将当期访问的点加入临时路径
tempPath.push_back(v);
//访问所有前驱
for(int i=0;i<pre[v].size();i++)
{
//递归遍历所有前驱
DFS(pre[v][i]);
}
tempPath.pop_back();
}
int main()
{
cin >> n >> m >> st >> ed;
for(int i=0;i<n;i++)
{
cin >> weight[i];
}
int u,v;
fill(G[0],G[0] + MAXV * MAXV,INF);
for(int i=0;i<m;i++)
{
cin >> u >> v;
cin >> G[u][v];
G[v][u] = G[u][v];
}
Dijkstra(st);
DFS(ed);
cout << totalCount << " " << optvalue << endl;
return 0;
}
PAT A1030 Travel Plan
#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXV = 510;
const int INF = 1000000000;
//n为顶点数,m为边数,st和ed分别为起点和终点
//G为距离矩阵,cost为花费矩阵
//d[]用来记录最短距离,minCost记录最短路径上的最小花费
int n,m,st,ed,G[MAXV][MAXV],cost[MAXV][MAXV];
int d[MAXV],minCost = INF;
//是否被访问过
bool vis[MAXV] = {false};
//前驱
vector<int> pre[MAXV];
vector<int> tempPath,path;//临时路径与最优路径
void Dijkstra(int s)
{
fill(d,d+MAXV,INF);
d[s] = 0;
//找出n个点
for(int i=0;i<n;i++)
{
int u = -1,MIN = INF;
//找最小路径且没有被访问的点
for(int j=0;j<n;j++)
{
if(vis[j] == false && d[j] < MIN)
{
u = j;
MIN = d[j];
}
}
//找不到则说明剩下的顶点和起点不连通
if(u == -1)
{
return;
}
vis[u] = true;
//更新d[]
for(int v = 0;v < n;v++)
{
//如果能到达则做为中转 ,看能否到达v,并判断以此为中转到v的距离是否比之前的d要小,如果小则更新
if(vis[v] == false && G[u][v] != INF)
{
if(d[u] + G[u][v] < d[v])
{
d[v] = d[u] + G[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if(d[u] + G[u][v] == d[v])
{
pre[v].push_back(u);
}
}
}
}
}
//v为当前节点
void DFS(int v)
{
//到达叶节点
if(v == st)
{
tempPath.push_back(v);
int tempCost = 0;//记录当前路径的花费之和
for(int i = tempPath.size() - 1;i > 0;i--)
{
int id = tempPath[i],idNext = tempPath[i-1];
tempCost += cost[id][idNext];
}
//如果小,则备份
if(tempCost < minCost)
{
minCost = tempCost;
path = tempPath;
}
//回溯
tempPath.pop_back() ;
return;
}
tempPath.push_back(v);
for(int i=0;i<pre[v].size();i++)
{
DFS(pre[v][i]);
}
tempPath.pop_back();
}
int main()
{
cin >> n >> m >> st >> ed;
int u,v;
fill(G[0],G[0]+MAXV*MAXV,INF) ;
for(int i=0;i<m;i++)
{
cin >> u >> v;
cin >> G[u][v];
cin >> cost[u][v];
G[v][u] = G[u][v];
cost[v][u] = cost[u][v];
}
Dijkstra(st);
DFS(ed);//获取最优路径
for(int i=path.size() - 1;i>=0;i--)
{
cout << path[i] << " ";
}
cout << d[ed] << " " << minCost << endl;
return 0;
}