L2-001緊急救助(25ポイント)
都市の緊急救助チームの責任者として、あなたは国の特別な地図を持っています。地図上には、複数の都市が点在しており、都市を結ぶ高速道路がいくつかあります。各都市の救助隊の数と2つの都市を結ぶ各高速道路の長さが地図上にマークされています。他の都市から緊急電話がかかってきた場合、あなたの仕事は、できるだけ早くあなたの救助隊を事件が起こった場所に導き、同時に、途中でできるだけ多くの救助隊を集めることです。
入力フォーマット:
最初の行を入力して、4つの正の整数N、M、S、Dを指定します。ここで、N(2≤N≤500)は都市の数です。ちなみに、都市の数は0〜(N-1)であると想定します。 ); Mは高速道路の数、Sは出発地の都市番号、Dは目的地の都市番号です。
2行目は、N個の正の整数を示します。ここで、i番目の数値はi番目の都市の救助チームの数であり、数値はスペースで区切られています。後続のM行では、各行に高速道路に関する情報が表示されます。つまり、都市1、都市2、および高速道路の長さがスペースで区切られ、数値はすべて整数で、500を超えません。入力により、レスキューが実行可能であり、最適なソリューションが一意であることが保証されます。
出力フォーマット:
最初の行は、組み立て可能な最短パスの数とレスキューチームの最大数を出力します。2行目は、SからDへのパスを通過した都市の番号を出力します。数字はスペースで区切られ、出力の最後に余分なスペースを入れることはできません。
入力サンプル:
4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2
サンプル出力:
2 60
0 1 3
問題解決
タイトルには、単一のソースの最短パスが必要ですが、最短パスの数、最短パス内の最適な頂点の重みを計算し、num []配列を使用してそれぞれの最短パスの数を記録する必要もあります。頂点、および最適な頂点の重みを記録するためのans []配列。、Num []最短パスが等しい符号をとるときに配列が追加されます。特定の実装は、コードによって異なります。
コード
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 5e2 + 2;
int G[maxn][maxn]; // 边权重
int V[maxn]; // 顶点权重
int dist[maxn], path[maxn];
int num[maxn]; // 记录最短路条数
int ans[maxn]; // 记录最优顶点权重
bool vis[maxn];
struct node{
int v;
int w;
};
struct cmp{
bool operator () (const node &a, const node &b){
return a.w > b.w;
}
};
void Dijkstra(int S, int D, int N){
memset(dist, 0x3f, sizeof(dist));
memset(path, -1, sizeof(path));
dist[S] = 0;
ans[S] = V[S];
num[S] = 1;
vis[S] = true;
priority_queue<node, vector<node>, cmp> q;
for(int i = 0; i < N; i++){
if(!vis[i] && G[S][i]){
q.push({
i, G[S][i]});
dist[i] = G[S][i];
path[i] = S;
num[i] = num[S];
ans[i] = ans[S] + V[i];
}
}
while(!q.empty()){
int v = q.top().v;
int w = q.top().w;
q.pop();
if(vis[v]) continue;
vis[v] = true;
for(int i = 0; i < N; i++){
if(!vis[i] && G[v][i]){
if(dist[v] + G[v][i] < dist[i]){
dist[i] = dist[v] + G[v][i];
q.push({
i, dist[i]});
num[i] = num[v]; // 单路径时, 接上一个
ans[i] = ans[v] + V[i];
path[i] = v;
} else if(dist[v] + G[v][i] == dist[i]){
num[i] += num[v]; // 重复路径时, 增加
// ans[i] = max(ans[i], ans[v] + V[i]);
if(ans[i] < ans[v] + V[i]){
ans[i] = ans[v] + V[i];
path[i] = v;
}
}
}
}
if(v == D) return;
}
}
void Print(int D, int S){
// 输出最优解
if(path[D] == -1 && D == S){
cout << D;
return;
}
Print(path[D], S);
cout << " " << D;
}
int main() {
int N, M, S, D;
cin >> N >> M >> S >> D;
for(int i = 0; i < N; i++) cin >> V[i];
int v1, v2, w;
for(int i = 0; i < M; i++){
cin >> v1 >> v2 >> w;
G[v1][v2] = G[v2][v1] = w;
}
Dijkstra(S, D, N);
cout << num[D] << " " << ans[D] << endl;
// for(int i = 0; i < N; i++){
// cout << dist[i] << " " << num[i] << " " << ans[i] << endl;
// }
Print(D, S);
return 0;
}