//迪杰斯特拉
//邻接矩阵版
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000; //最大顶点数
const int INF = 1000000;
int n, m, s, G[maxn][maxn]; //n为顶点数,m为边数,s为起点,G邻接矩阵
int d[maxn]; //起点到各个顶点的最短路径长度
int pre[maxn]; //结点的前驱
bool vis[maxn] = {false}; //标记是否访问
void Dijkstra(int s)
{
fill(d, d + maxn, INF);
d[s] = 0;
//n次循环
for(int i = 0; i < n; i++)
{
int u = -1, MIN = INF; //使d[u]最小的还未被访问过的顶点的标号 MIN存放最小的d[u]
for(int j = 0; j < n; j++) //找到未访问顶点中d[]最小的
{
if(vis[j] == false && d[j] < MIN)
{
u = j;
MIN = d[j];
}
}
if(u == -1) return; //找不到小于INF的d[u],说明剩下的顶点和s不连通
vis[u] = true; //标记u已经被访问
for(int v = 0; v < n; v++) //从u出发能到达的所有顶点
{
//如果v未访问&&u能到达v&&以u为中介可以使得d[v]更优
if(vis[v] == false && G[u][v] != INF && G[u][v] + d[u] < d[v])
{
d[v] = G[u][v] + d[u];
pre[v] = u;
}
}
}
}
void DFS(int s,int v) //输出最短路径
{
if(v == s)
{
printf("%d ", s);
return;
}
DFS(s, pre[v]);
printf("%d ", v);
}
int main()
{
int u, v, w;
scanf("%d%d%d", &n, &m, &s); //n为顶点数,m为边数,s为起点
fill(G[0], G[0] + maxn * maxn, INF);
for(int i = 0; i < m; i++)
{
scanf("%d%d%d", &u, &v, &w); //有向边
G[u][v] = w;
//如果是无向边,只需要把无向边堪称两条相反的有向边即可
//对于邻接矩阵,G[u][v]和G[v][u]赋相同的权值即可
//对于邻接表,Adj[v]加上u,Adj[u]加上v即可
}
Dijkstra(s);
for(int i = 0; i < n; i++)
printf("%d ", d[i]);
printf("\n");
DFS(0, 2);
return 0;
}
//迪杰斯特拉
//邻接表版
#include<bits/stdc++.h>
using namespace std;
const int maxv = 1000;
const int INF = 100000000;
struct node
{
int v, dis; // v为边的目标顶点,dis为边权
};
vector<node> Adj[maxv]; //图G
int n;
int d[maxv]; //到各个点的最短距离
bool vis[maxv] = {false};
void Dijkstra(int s)
{
fill(d, d + maxv, INF);
d[s] = 0;
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[u];
}
}
if(u == -1) return;
vis[u] = true;
//只有这里跟邻接矩阵版不同
for(int j = 0; j < Adj[u].size(); j++) //从u能到达的所有顶点
{
int v = Adj[u][j].v; //通过邻接表直接获得u能到达的顶点v
if(vis[v] == false && d[u] + Adj[u][j].dis < d[v])
{
d[v] = d[u] + Adj[u][j].dis;
}
}
}
}
int main()
{
return 0;
}
第二标尺的情况:
1、给每条边再增加一个边权(比如花费),要求有多条路径时求最少的花费。
2、给每个点再增加一个点权(例如每个城市能收集到的物资),要求有多条路径时求路径上的点权之和最大
3、直接问有多少条最短路径
1、新增边权。用cost[u][v]代表u到v的花费,增加一个数组c[ ],c[u]表示起点s到u的最小花费,初始化c[s] = 0,其余c[u] = INF
for(int v = 0; v < n; v++)
{
if(vis[v] == false && G[u][v] != INF)
{
if(G[u][v] + d[u] < d[v]) //以u为中介点可以使d[v]更优
{
d[v] = G[u][v] + d[u];
c[v] = c[u] + cost[u][v];
}
else if(G[u][v] + d[u] == d[v] && c[u] + cost[u][v] <c[v]) //相同距离看是否能使C[v]更优
{
c[v] = c[u] + cost[u][v];
}
}
}
**2、新增点权。**以点权代表能收集到的物资为例,weight[u] 表示城市 u 的物资数,增加一个数组 w[ ],w[u]表示从起点s到u能收集到的最大物资。初始化w[s] = weight[s],其余w[u] = 0。
for(int v = 0; v < n; v++)
{
if(vis[v] == false && G[u][v] != INF)
{
if(G[u][v] + d[u] < d[v]) //以u为中介点可以使d[v]更优
{
d[v] = G[u][v] + d[u];
w[v] = w[u] + weight[v];
}
else if(G[u][v] + d[u] == d[v] && w[u] + weight[v] > w[v]) //最短距离相同时看是否能使w[v]更优
{
w[v] = weight[u] + weight[v];
}
}
}
**3、求最短路径条数。**新增一个数组num[ ]表示最短路径条数,初始化num[s] = 1,其余num[u] = 0。
for(int v = 0; v < n; v++)
{
if(vis[v] == false && G[u][v] != INF)
{
if(G[u][v] + d[u] < d[v]) //以u为中介点可以使d[v]更优
{
d[v] = G[u][v] + d[u];
num[v] = num[u] //距离更小时,继承到u的结果
}
else if(G[u][v] + d[u] == d[v])
{
num[v] += num[u]; //距离相同时累加
}
}
}