//迪杰斯特拉
//邻接矩阵版
#include<bits/stdc++.h>
using namespace std;
const int maxn = 510; //最大顶点数
const int INF = 1000000;
int n, m, st, ed, weight[maxn], G[maxn][maxn]; //n为顶点数,m为边数,s为起点,G邻接矩阵
int d[maxn], w[maxn], num[maxn]; //起点到各个顶点的最短路径长度
//int pre[maxn]; //结点的前驱
bool vis[maxn] = {false}; //标记是否访问
void Dijkstra(int s)
{
fill(d, d + maxn, INF);
memset(w, 0, sizeof(w));
memset(num, 0, sizeof(num));
d[s] = 0;
w[s] = weight[s];
num[s] = 1;
//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++)
{
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];
num[v] = num[u];
}
// else if(G[u][v] + d[u] == d[v] && w[u] + weight[v] > w[v])
else if(G[u][v] + d[u] == d[v])
{
if(w[u] + weight[v] > w[v])
{
w[v] = w[u] + weight[v];
}
num[v] += num[u]; //最短路径与点权无关,必须写在外面
}
}
}
}
}
//void DFS(int s,int v) //输出最短路径
//{
// if(v == s)
// {
// printf("%d ", s);
// return;
// }
// DFS(s, pre[v]);
// printf("%d ", v);
//}
int main()
{
scanf("%d%d%d%d", &n, &m, &st, &ed);
// scanf("%d%d%d", &n, &m, &s); //n为顶点数,m为边数,s为起点
for(int i = 0; i < n; i++)
scanf("%d", &weight[i]);
int u, v;
fill(G[0], G[0] + maxn * maxn, INF);
for(int i = 0; i < m; i++)
{
scanf("%d%d", &u, &v); //有向边
scanf("%d", &G[u][v]);
G[v][u] = G[u][v];
// G[u][v] = w;
//如果是无向边,只需要把无向边堪称两条相反的有向边即可
//对于邻接矩阵,G[u][v]和G[v][u]赋相同的权值即可
//对于邻接表,Adj[v]加上u,Adj[u]加上v即可
}
Dijkstra(st);
printf("%d %d", num[ed], w[ed]);
// DFS(0, 2);
return 0;
}
这样也可以,区别主要在于那个for循环条件的个数。
//迪杰斯特拉
//邻接矩阵版
#include<bits/stdc++.h>
using namespace std;
const int maxn = 510; //最大顶点数
const int INF = 1000000;
int n, m, st, ed, weight[maxn], G[maxn][maxn]; //n为顶点数,m为边数,s为起点,G邻接矩阵
int d[maxn], w[maxn], num[maxn]; //起点到各个顶点的最短路径长度
//int pre[maxn]; //结点的前驱
bool vis[maxn] = {false}; //标记是否访问
void Dijkstra(int s)
{
fill(d, d + maxn, INF);
memset(w, 0, sizeof(w));
memset(num, 0, sizeof(num));
d[s] = 0;
w[s] = weight[s];
num[s] = 1;
//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++)
{
if(vis[v] == false && G[u][v] != INF && G[u][v] + d[u] < d[v])
{
//以u为中介点可以使d[v]更优
d[v] = G[u][v] + d[u];
w[v] = w[u] + weight[v];
num[v] = num[u];
}
// else if(G[u][v] + d[u] == d[v] && w[u] + weight[v] > w[v])
else if(vis[v] == false && G[u][v] != INF && G[u][v] + d[u] == d[v])
{
if(w[u] + weight[v] > w[v])
{
w[v] = w[u] + weight[v];
}
num[v] += num[u];
}
}
}
}
//void DFS(int s,int v) //输出最短路径
//{
// if(v == s)
// {
// printf("%d ", s);
// return;
// }
// DFS(s, pre[v]);
// printf("%d ", v);
//}
int main()
{
scanf("%d%d%d%d", &n, &m, &st, &ed);
// scanf("%d%d%d", &n, &m, &s); //n为顶点数,m为边数,s为起点
for(int i = 0; i < n; i++)
scanf("%d", &weight[i]);
int u, v;
fill(G[0], G[0] + maxn * maxn, INF);
for(int i = 0; i < m; i++)
{
scanf("%d%d", &u, &v); //有向边
scanf("%d", &G[u][v]);
G[v][u] = G[u][v];
// G[u][v] = w;
//如果是无向边,只需要把无向边堪称两条相反的有向边即可
//对于邻接矩阵,G[u][v]和G[v][u]赋相同的权值即可
//对于邻接表,Adj[v]加上u,Adj[u]加上v即可
}
Dijkstra(st);
printf("%d %d", num[ed], w[ed]);
// DFS(0, 2);
return 0;
}
最短路径
//迪杰斯特拉
//邻接矩阵版
#include<bits/stdc++.h>
using namespace std;
const int maxn = 510; //最大顶点数
const int INF = 1000000;
int n, m, s; //n为顶点数,m为边数,s为起点,G邻接矩阵
int d[maxn], G[maxn][maxn]; //起点到各个顶点的最短路径长度
int pre[maxn]; //结点的前驱
bool vis[maxn] = {false}; //标记是否访问
void Dijkstra(int s)
{
fill(d, d + maxn, INF);
for(int i = 0; i < n; i++)
pre[i] = i; //初始状态每个节点的前驱为自身(新增)
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为中介点可以使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; //记录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;
}
Dijkstra(s);
for(int i = 0; i < n; i++)
printf("%d ", d[i]);
printf("\n到各个点的距离为:\n");
for(int i = 0; i < n; i++)
{
printf("\n");
DFS(0, i);
}
return 0;
}
输入:
6 8 0
0 1 1
0 3 4
0 4 4
1 3 2
2 5 1
3 2 2
3 4 3
4 5 3
输出
0 1 5 3 4 6
到各个点的距离为:
0
0 1
0 1 3 2
0 1 3
0 4
0 1 3 2 5
之前的写法中,pre[i]初始化为i,这种写法pre[v]并不需要初始化。
如果G[u][v] + d[u] < d[v],说明以u为中介可以使d[v]更优,此时pre[v]要先清空,然后再添加u。
if(G[u][v] + d[u] < d[v])
{
d[v] = G[u][v] + d[u]
pre[v].clear();
pre[v].push_back(u);
}
如果G[u][v] + d[u] = d[v],此时只需要再原来的基础上添加u
if(G[u][v] + d[u] == d[v])
pre[v].push_back(u);
vector<int> pre[maxn];
void Dijkstra_1(int s)
{
fill(d, d + maxn, 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] < INF)
{
u = j;
MIN = d[j];
}
}
if(u == -1) return;
vis[u] == true;
for(int v = 0; v < n; v++)
{
if(vis[v] == false && &&G[u][v] != INF)
{
if(G[u][v] + d[u] < d[v])
{
d[v] = G[u][v] + d[u]
pre[v].clear();
pre[v].push_back(u); //令v的前驱为u
}
else if(G[u][v] + d[u] == d[v])
{
pre[v].push_back(u); //令v的前驱为u
}
}
}
}
}
SPFA做法:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=501;
const int INF=1000000;
int n, m, st, ed, weight[MAXN];
int d[MAXN], w[MAXN], num[MAXN], cnt[MAXN]; //num路径条数, cnt入队次数
bool inq[MAXN] = {false};
set<int> pre[MAXN];
struct Node{
int v,dis;
Node(int _v,int _dis):v(_v),dis(_dis){
};//构造函数
};
vector<Node> Adj[MAXN];
bool SPFA(int s){
fill(d,d+MAXN,INF);
memset(w,0,sizeof(w));
memset(num,0,sizeof(num));
queue<int> Q;
Q.push(s);
//s在队列里
inq[s]=true;
d[s]=0;
w[s]=weight[s];
num[s]=1;
cnt[s]=1;//源点入队次数+1
while(!Q.empty()){
int u=Q.front();
Q.pop();
inq[u]=false;
for(int j=0;j<Adj[u].size();j++){
int v=Adj[u][j].v;
int dis=Adj[u][j].dis;
if(d[u]+dis<d[v]){
d[v]=d[u]+dis;
w[v]=w[u]+weight[v];
pre[v].clear();
pre[v].insert(u);
num[v]=num[u];
if(!inq[v]){
Q.push(v);
//v的入队次数+1
cnt[v]++;
inq[v]=true;
}
}else if(d[u]+dis==d[v]){
if(w[u]+weight[v]>w[v]){
w[v]=w[u]+weight[v];
}
pre[v].insert(u);
num[v]=0; //重新统计num[v]
set<int>::iterator it;
for(it=pre[v].begin();it!=pre[v].end();it++){
num[v]+=num[*it];
}
//无论w[v]是否改变,num[v]都有可能改变,所以入队
if(!inq[v]){
Q.push(v);
cnt[v]++;
inq[v]=true;
}
}
//只要某一点入队次数>=n
//则原图中有负环,则不可得到结果
if(cnt[v]>=n) return false;
}
}
return true;
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d%d%d",&n,&m,&st,&ed);
for(int i=0;i<n;i++){
scanf("%d",&weight[i]);
}
int u,v,wt;
for(int i=0;i<m;i++){
scanf("%d%d%d",&u,&v,&wt);
Adj[u].push_back(Node(v,wt));
Adj[v].push_back(Node(u,wt));
}
bool ok=SPFA(st);
if(ok) printf("%d %d",num[ed],w[ed]);
else printf("有负环!");
return 0;
}