L2-001 紧急救援 (25分)
个人wa点:求最短路径的条数(有多少条最短路径),以及能够召集的最多的救援队数量输出最多召集的路径
#include<iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <functional>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <algorithm>
#define ll long long
#define PI acos(-1)
#define mes(x,y) memset(x,y,sizeof(x))
#define lp pair<ll, ll>
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const ll inf = 5e9 + 30;
ll n, m, i, j, k, t, flag, x, y, z;
string s1, s2, s;
ll gram[510][510],value[510],father[510],sumvalue[510],minlen[510],step[510],f[510];
//相互之间的距离,每个的权值,这个点的上一级,总权值,最短路径长度,开始位置到此处的要经过的点的个数,此点是否已走过
void Dijkstra(ll begin) {
fill(minlen,minlen+n,inf); mes(sumvalue, 0); mes(step, 0); mes(f, 1);
minlen[begin] = 0; sumvalue[begin] = value[begin]; step[begin] = 1;
for (i = 0; i < n; i++) {
ll now = -1, minn = inf;
for (j = 0; j < n; j++) {
if (f[j] && minlen[j] < minn) {
minn = minlen[j]; now = j;
}
}
// cout << endl << now << endl;
if (now == -1)break;
f[now] = 0;
for (j = 0; j < n; j++) {
if (f[j] == 0 || gram[now][j] == inf)continue;
//cout << j << ":" << endl;
//cout << minlen[now] << "+" << gram[now][j] << " " << minlen[j] << endl;
if (minlen[now] + gram[now][j] < minlen[j]) {
minlen[j] = minlen[now] + gram[now][j];
sumvalue[j] = sumvalue[now] + value[j];
father[j] = now; step[j] = step[now];
//cout << 1 << " " << step[j] << endl;
}
else if (minlen[now] + gram[now][j] == minlen[j]) {
//cout << sumvalue[j] << " " << sumvalue[now] << "+" << value[j] << endl;
if (sumvalue[j] < sumvalue[now] + value[j]) {
sumvalue[j] = sumvalue[now] + value[j];
father[j] = now;
}
step[j] += step[now];
//cout << 2 << " " << step[j] << endl;
}
//cout << minlen[j] << ":" << sumvalue[j] << endl << endl;
}
}
}
void finfather(ll begin,ll mid) {
if (begin==mid) {
cout << begin;
return;
}
finfather(begin, father[mid]);
cout<<" " << mid;
}
int main() {
FAST_IO; ll a, b;
while (cin >> n >> m >> a >> b) {
fill(gram[0], gram[0] + 510 * 510, inf);
//cout << gram[0][0] << endl;
for (i = 0; i < n; i++)cin >> value[i];
for (i = 0; i < m; i++) {
cin >> x >> y >> z;
gram[x][y] = gram[y][x] = z;
}
//cout << gram[1][2] << endl;
Dijkstra(a);
cout << step[b] << " " << sumvalue[b] << endl;
finfather(a, b); cout << endl;
}
}
教学版(应该只有我自己能看懂)
#include<iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <functional>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <algorithm>
#define ll long long
#define PI acos(-1)
#define mes(x,y) memset(x,y,sizeof(x))
#define lp pair<ll, ll>
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const ll inf = 5e9 + 30;
ll n, m, i, j, k, t, flag, x, y, z;
string s1, s2, s;
struct node {
ll father;
//此点的父亲节点(一开始点为最大辈的点)
ll value;
//开始点一直到此点的最大权值
ll len;
//开始点到此点的最短路径
ll step;
//开始点到此点所有最短路径有多少条
}point[510];
ll gram[510][510];
//相互之间的距离
ll value[510];
//每个点的权值
ll f[510];
//判断此点此点是否已无到它的最短路径
void Dijkstra(ll begin,ll end) {
for (i = 0; i < 510; i++) {
point[i].len = inf;
point[i].step = point[i].father = point[i].value = 0;
}//赋予默认值
point[begin].len = 0;
//并未开始出发,因此最一开始的长度为0
point[begin].value = value[begin];
//权值为此点的权值
point[begin].step = 1;
//开始点只有一条路径到达它自己
for (i = 0; i <n; i++) {
ll now = -1, minn = inf;
for (j = 0; j < n; j++)
if (!f[j] && point[j].len < minn)
minn = point[j].len,now = j;
//找到开始点到now最短的那一条路径
if (now == end)break;
//如果now到end点已经是最短路径了,那么接下来,
//1.end点不会再成为最后末点出现
//2.后面也不会出现以后面的路径为跳板的到end点的最短路径
f[now] = 1;
//代表从此刻开始now不在作为末点出现
for (j = 0; j < n; j++) {
if (f[j] || gram[now][j] == inf)continue;
//确保此点未被走过并且这now和j两点之间有路
if (point[now].len + gram[now][j] < point[j].len) {
//如果开始到now的距离加上now到j的距离小于原本的路径
point[j].len = point[now].len + gram[now][j];
//即修改此点到开始的距离
point[j].value = point[now].value + value[j];
//并修改权值
point[j].father = now;
//将此点列入最后输出最大权值路径
point[j].step = point[now].step;
//采用dp,有几种路径到now,就有几种路径可以从now到j
//由于路径长度有所改变,那么到j点的路径需要覆盖。
}
else if (point[now].len + gram[now][j] == point[j].len) {
//如果开始到now的距离加上now到j的距离等于原本的路径
if (point[now].value + value[j] > point[j].value) {
//查看权值比现在的路径上的权值小
point[j].value = point[now].value + value[j];
//修改权值
point[j].father = now;
//以及修改此点未当前路径上的点
}
point[j].step += point[now].step;
//采用dp,有几种路径到now,就有几种路径可以从now到j
//由于路径长度未有所改变
//那么到now点的那几条路径属于是最短路径那么到j点的路径需要累加起来。
}
}
}
}
void finfather(ll begin, ll mid) {
if (begin == mid) {
cout << begin;
return;
//先输出开始点
}
finfather(begin, point[mid].father);
cout << " " << mid;
//依次输出剩下的点
}
int main() {
FAST_IO; ll a, b;
while (cin >> n >> m >> a >> b) {
fill(gram[0], gram[0] + 510 * 510, inf);
//第一次接触fill,记录一下
for (i = 0; i < n; i++)cin >> value[i];
for (i = 0; i < m; i++) {
cin >> x >> y >> z;
gram[x][y] = gram[y][x] = z;
}
//赋值,路径是双向的
Dijkstra(a,b);
cout << point[b].step << " " << point[b].value << endl;
finfather(a, b); cout << endl;
}
}