需要二刷【二刷了,更新在下面了】
Dijkstra邻接矩阵
# include <iostream>
# include <vector>
# include <algorithm>
using namespace std;
const int INF = 0xffff;
/*
城市数N 路数M 起始城市C1 终点城市C2
N个城市中的救援队数量
M条路(弧头 弧尾 路的长度(权重))
*/
typedef int INDEX;
struct CityGraph
{
vector<int> vexs; // 城市 --顶点表(存储了顶点的信息)
vector<vector<int>> arcs; // 路 --邻接矩阵(存储了边的权值,不存在边就为无穷大INF ∞)
int vexnum; // 城市数 --图中的当前顶点数
int arcnum; // 路径数 --图中的当前边数
INDEX C1; // 起始城市
INDEX C2; // 终点城市
CityGraph()
{
cin >> vexnum >> arcnum >> C1 >> C2;
vexs = vector<int>(vexnum);
for(int & i: vexs){
cin >> i;
}
arcs = vector<vector<int>>(vexnum, vector<int>(vexnum, INF));
int a, b, weight;
for(int i=0;i<arcnum;i++){
cin >> a >> b >> weight; // a->b
arcs[a][b] = weight;
arcs[b][a] = weight;
}
}
INDEX findMinDistIndex(const vector<bool> &S, const vector<int> &dist)
{
int idx = -1;
int mindist = INF;
for(int i=0;i<vexnum;i++){
if(S[i] == false && dist[i] < mindist){
mindist = dist[i];
idx = i;
}
}
return idx;
}
void finMinDistANDMaxTeamAmount()
{
int mindist;
vector<bool> S (vexnum, false); // 标记i顶点是否加入到最短路径中(是否被访问过)
vector<int> dist(vexnum, INF-10); // 每个dist[i]表示起始点C1到Ci的最短路径的长度
vector<int> num (vexnum, 0); // 最短路径的数量(可能有相同长度的最短的路径、用这个代替path数组统计最短路径数量就可以了)
vector<int> team(vexnum, 0); // 每个team[i]表示起始点C1到Ci的最大救援队数量
dist[C1] = 0;
num[C1] = 1;
team[C1] = vexs[C1];
// 循环到所有顶点已加入最短路径
for(int i=0;i<vexnum;i++)
{
mindist = findMinDistIndex(S, dist);
if(mindist == -1)
break;
S[mindist] = true;
for(int j=0;j<vexnum;j++){
long pathdist = dist[mindist] + arcs[mindist][j];
int teammax = team[mindist] + vexs[j];
if(S[j] == false && dist[j] > pathdist){
num[j] = num[mindist];
dist[j] = pathdist;
team[j] = teammax;
}
else
if(S[j] == false && dist[j] == pathdist){
num[j] += num[mindist];
team[j] = max(teammax, team[j]);
}
}
}
cout << num[C2] << " ";
cout << team[C2]<< endl;
}
void print_path_dist(vector<int> & dist,vector<int> & path)
{
printf("i dist path\n");
for(int i=0;i<vexnum;i++){
printf("%d %2d %2d\n", i, dist[i], path[i]);
}
}
void showVexs()
{
for(int i: vexs){
cout << i << " ";
}cout << endl;
}
void showArcs()
{
for(vector<int> i: arcs){
for(int j: i){
if(j == INF)
cout << "∞ ";
else
printf("%2d ", j);
}cout << endl;
}cout << endl;
}
};
int main()
{
CityGraph G;
// G.showVexs();
// G.showArcs();
G.finMinDistANDMaxTeamAmount();
return 0;
}
二刷 Dijkstra邻接表
# include <iostream>
# include <vector>
# include <algorithm>
using namespace std;
int N; // 顶点数
int M; // 边数
int C1; // 源点
int C2; // 终点
const int INF = 0xffffff;
struct Node{
int v; // 边的弧尾
int weight; // u-v边权
};
vector<Node> Adj[550]; // 邻接表(保存邻接边的权重(城市之间距离))
vector<int> V(550); // 顶点表(保存点的权重(城市队伍数量))
vector<int> pathnum(550); // path[C2]为源点C1到终点C2的最短路径的数量
vector<int> dist(550); // dist[C2]为源点C1到终点C2的最短路径长度
vector<int> team(550); // team[C2]为在最快从C1到达C2的条件下,从源点C1出发到达C2能找到最多救援队数量
vector<int> vis(550); // 标记访问
void Dijkstra(int s){ // s是源点
fill(begin(pathnum), end(pathnum), 0);
fill(begin(dist), dist.end(), INF);
fill(begin(team), end(team), 0);
fill(begin(vis), end(vis), false);
dist[s] = 0;
team[s] = V[s];
pathnum[s] = 1;
for(int i = 0;i<N;++i){
// 寻找未访问顶点中和源点最短路径最小的那个顶点
int u = -1;
int MIN = INF;
for(int j = 0;j<N;++j){
if(vis[j] == false && dist[j] < MIN){
u = j;
MIN = dist[j];
}
}
if(u == -1) return;
vis[u] = true;
for(int j = 0;j<Adj[u].size();++j){
int v = Adj[u][j].v;
if(vis[v] == false && dist[u] + Adj[u][j].weight < dist[v]){
dist[v] = dist[u] + Adj[u][j].weight;
team[v] = team[u] + V[v];
pathnum[v] = pathnum[u];
}
else
if(vis[v] == false && dist[u] + Adj[u][j].weight == dist[v]){
/* 在多条最短路径中选择队伍最多(点权和最大)的一种(
也就是说team[v]和dist[v]可能不是同一条最短路径上的数据 */
team[v] = max(team[u] + V[v], team[v]);
pathnum[v] = pathnum[v] + pathnum[u];
}
}
}
}
int main() {
cin >> N >> M >> C1 >> C2;
for(int i = 0;i<N;++i)
cin >> V[i];
for(int i = 0;i<M;++i){
int c1, c2, length;
cin >> c1 >> c2 >> length;
Adj[c1].push_back({c2, length});
Adj[c2].push_back({c1, length}); // 记住是双向边,不然会导致测试点2、5错误
}
Dijkstra(C1);
cout << pathnum[C2] << " " << team[C2];
return 0;
}
二刷 Dijkstra + DFS 邻接表
# include <iostream>
# include <vector>
# include <algorithm>
using namespace std;
int N; // 顶点数
int M; // 边数
int C1; // 源点
int C2; // 终点
const int INF = 0xffffff;
const int MAXV = 550;
struct Node{
int v; // 边的弧尾
int weight; // u-v边权
};
vector<Node> Adj[MAXV]; // 邻接表(保存邻接边的权重(城市之间距离))
vector<int> V(MAXV); // 顶点表(保存点的权重(城市队伍数量))
vector<int> dist(MAXV); // dist[C2]为源点C1到终点C2的最短路径长度
vector<int> vis(MAXV); // 标记访问
vector<int> pre[MAXV];
void Dijkstra(int s){
fill(begin(dist), dist.end(), INF);
fill(begin(vis), end(vis), false);
dist[s] = 0;
for(int i = 0;i<N;++i){
int u = -1;
int MIN = INF;
for(int j = 0;j<N;++j){
if(vis[j] == false && dist[j] < MIN){
u = j;
MIN = dist[j];
}
}
if(u == -1) return;
vis[u] = true;
for(int j = 0;j<Adj[u].size();++j){
int v = Adj[u][j].v;
if(vis[v] == false && dist[u] + Adj[u][j].weight < dist[v]){
dist[v] = dist[u] + Adj[u][j].weight;
pre[v].clear();
pre[v].push_back(u);
}
else
if(vis[v] == false && dist[u] + Adj[u][j].weight == dist[v]){
pre[v].push_back(u);
}
}
}
}
int maxPathNum = 0; // 最大最短路径数
int maxTeamNum; // 第二标尺最优值
vector<int> path, temppath; // 根据第二标尺获得:最优路径、临时路径
void DFS(int v){
// 递归边界(死胡同)
if(v == C1){
// 因为递归边界是叶子结点,也就是从终点到达起点的次数,
// 也就是最短路径的条数,所以每次就自增就可得到最短路径的条数
maxPathNum++;
temppath.push_back(C1);
// 计算临时第二标尺值
int teamnum = 0;
for(int t: temppath){
teamnum += V[t]; // 记住t是最短路径上的顶点索引,teamnum加的是顶点权重V[t]
}
// 如果临时第二标尺值比已知最大值大,那就更新全局第二标尺值
if(teamnum > maxTeamNum){
maxTeamNum = teamnum;
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 >> C1 >> C2;
for(int i = 0;i<N;++i)
cin >> V[i];
for(int i = 0;i<M;++i){
int c1, c2, length;
cin >> c1 >> c2 >> length;
Adj[c1].push_back({c2, length});
Adj[c2].push_back({c1, length}); // 记住是双向边,不然会导致测试点2、5错误
}
Dijkstra(C1);
DFS(C2);
cout << maxPathNum << " " << maxTeamNum;
return 0;
}
过段时间又写了一遍
#include<bits/stdc++.h>
using namespace std;
const int INF = 0xffffff;
int N, M, C1, C2;
struct Node{
int v, weight;
};
int dist[510];
bool visit[510] = {false};
int team[510];
vector<Node> G[510];
vector<int> pre[510];
void Dijkstra(int s){
fill(dist, end(dist), INF);
dist[s] = 0;
for(int i = 0;i < N;++i) {
int u = -1;
int mindist = INF;
for(int j = 0;j < N;j++){
if(visit[j] == false && dist[j] < mindist) {
u = j;
mindist = dist[j];
}
}
if(u == -1) return;
visit[u] = true;
for(Node node: G[u]) {
int v = node.v, u_v = node.weight;
if(visit[v] == false && dist[u] + u_v < dist[v]) {
dist[v] = dist[u] + u_v;
pre[v].clear();
pre[v].push_back(u);
} else
if(visit[v] == false && dist[u] + u_v == dist[v]) {
pre[v].push_back(u);
}
}
}
}
vector<int> tempPath;
int maxTeam = 0, pathNum = 0;
void DFS(int u) {
if(u == C1){
tempPath.push_back(u);
pathNum++;
int tempTeam = 0;
for(int i: tempPath)
tempTeam += team[i];
maxTeam = min(maxTeam, tempTeam);
tempPath.pop_back();
return;
}
tempPath.push_back(u);
for(int v: pre[u])
DFS(v);
tempPath.pop_back();
}
int main() {
cin >> N >> M >> C1 >> C2;
for(int i = 0;i < N;++i)
cin >> team[i];
for(int i = 0;i < M;++i){
int u, v, len;
cin >> u >> v >> len;
G[u].push_back({v, len});
G[v].push_back({u, len});
}
Dijkstra(C1);
DFS(C2);
cout << pathNum << " " << maxTeam << endl;
return 0;
}