分析
使用Dijkstra算法或Bellman-Ford都可以
算法一:Dijkstra
//
// Created by CyIce on 2021/1/19.
//
#include <stdio.h>
#include <algorithm>
using namespace std;
const int MAXV = 510;
const int INF = 0x3fffffff;
//Team:每个城市的救援队数量
int n, G[MAXV][MAXV], Team[MAXV], pathNum = 0, teamNum = 0;
//d[i]:起点到i的最短路径,t[i]:起点到i最短路径下救援队的最大数量,num[i]:起点到i最短路径的数目
int d[MAXV], t[MAXV] = {0}, num[MAXV]={0};
bool vis[MAXV] = {false};
void Dijkstra(int s, int e) {
fill(d, d + MAXV, INF);
num[s]=1;
d[s] = 0;
t[s] = Team[s];
for (int i = 0; i < n; ++i) {
int u = -1, MIN = INF;
for (int j = 0; j < n; ++j) {
if (!vis[j] && d[j] < MIN) {
u = j;
MIN = d[j];
}
}
if (u == -1) return;
vis[u] = true;
for (int v = 0; v < n; ++v) {
if (!vis[v] && G[u][v] != INF) {
if (d[u] + G[u][v] < d[v]) {
d[v] = d[u] + G[u][v];
t[v] = t[u] + Team[v];
num[v] = num[u];
} else if (d[u] + G[u][v] == d[v]) {
num[v] += num[u];
if (t[u] + Team[v] > t[v])
t[v] = t[u] + Team[v];
}
}
}
}
pathNum = num[e];
teamNum = t[e];
}
int main() {
int edge, s, e;
fill(G[0], G[0] + MAXV * MAXV, INF);
scanf("%d%d%d%d", &n, &edge, &s, &e);
for (int i = 0; i < n; ++i) {
scanf("%d", &Team[i]);
}
for (int i = 0; i < edge; ++i) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
G[a][b] = c;
G[b][a] = c;
}
Dijkstra(s, e);
printf("%d %d\n", pathNum, teamNum);
return 0;
}
算法二:Bellman-Ford
//
// Created by CyIce on 2021/1/24.
//
//Bellman-Ford算法
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
//边结构体
struct edge {
int v, dis;
};
const int MAXV = 510;
//邻接矩阵
vector<edge> Adj[MAXV];
int N, V[MAXV], INF = 0x3fffffff;
//最短路径和最大救援队数量
int d[MAXV], value[MAXV] = {0};
//前驱节点,因为每个节点会重复访问,用set避免同一节点重复添加
set<int> pre[MAXV];
bool bellman(int s) {
fill(d, d + MAXV, INF);
d[s] = 0;
value[s] = V[s];
for (int i = 0; i < N - 1; ++i) {
for (int u = 0; u < N; ++u) {
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;
value[v] = value[u] + V[v];
pre[v].clear();
pre[v].insert(u);
} else if (d[u] + dis == d[v]) {
if(value[u] + V[v] > value[v]){
value[v] = value[u] + V[v];
}
pre[v].insert(u);
}
}
}
}
for (int i = 0; i < N - 1; ++i) {
for (int u = 0; u < N; ++u) {
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]) {
return false;
}
}
}
}
return true;
}
//递归计算最短路径条数
//s:起点,v:当前节点
int pathNum(int s,int v){
if(v == s){
return 1;
} else{
set<int>::iterator it;
int num=0;
for(it = pre[v].begin();it!=pre[v].end();it++){
num+=pathNum(s,*it);
}
return num;
}
}
int main() {
int m, s, end;
scanf("%d%d%d%d", &N, &m, &s, &end);
for (int i = 0; i < N; ++i) {
scanf("%d", &V[i]);
}
for (int i = 0; i < m; ++i) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
Adj[a].push_back(edge{b, c});
Adj[b].push_back(edge{a, c});
}
if (bellman(s)) {
printf("%d %d\n", pathNum(s,end), value[end]);
}
return 0;
}
解法三:SPFA (测试点2未通过,原因未知)
#include <stdio.h>
#include <vector>
#include <queue>
#include <set>
#include <algorithm>
using namespace std;
struct node {
int v, dis;
};
const int MAXV = 510;
int INF = 0x3fffffff;
vector<node> Adj[MAXV];
set<int> pre[MAXV];
int N, d[MAXV], value[MAXV] = {0}, V[MAXV], num[MAXV] = {0};
bool inq[MAXV] = {false};
bool SPFA(int s) {
fill(d, d + MAXV, INF);
queue<int> q;
q.push(s);
inq[s] = true;
num[s]++;
d[s] = 0;
value[s] = V[s];
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = false;
for (int i = 0; i < Adj[u].size(); ++i) {
int v = Adj[u][i].v;
int dis = Adj[u][i].dis;
if (d[u] + dis < d[v]) {
d[v] = d[u] + dis;
value[v] = value[u] + V[v];
pre[v].clear();
pre[v].insert(u);
if (!inq[v]) {
q.push(v);
inq[v] = true;
num[v]++;
if (num[v] >= N)
return false;
}
} else if (d[u] + dis == d[v]){
pre[v].insert(u);
if(value[u] + V[v] > value[v]){
value[v] = value[u] + V[v];
}
}
}
}
return true;
}
//递归计算最短路径条数
//s:起点,v:当前节点
int pathNum(int s,int v){
if(v == s){
return 1;
} else{
set<int>::iterator it;
int num=0;
for(it = pre[v].begin();it!=pre[v].end();it++){
num+=pathNum(s,*it);
}
return num;
}
}
int main() {
int m, s, end;
scanf("%d%d%d%d", &N, &m, &s, &end);
for (int i = 0; i < N; ++i) {
scanf("%d", &V[i]);
}
for (int i = 0; i < m; ++i) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
Adj[a].push_back(node{b, c});
Adj[b].push_back(node{a, c});
}
if (SPFA(s)) {
printf("%d %d\n", pathNum(s, end), value[end]);
}
return 0;
}