1003 Emergency
题目大意
n
n
n 个点,
m
m
m 条边的无向图,点有点权。
求从
C
1
C1
C1 到
C
2
C2
C2 的最短路径,最短路径的数量,以及最短路径中最大的点权和。保证
C
1
C1
C1 和
C
2
C2
C2 是连通的。
数据范围:
n
≤
500
n \leq 500
n≤500
猜测:各种数据不超过 int,没有重边。
方法一 spfa+dfs
思路
spfa求最短路以及最短路中的最大点权和
dfs求最短路的数量
错误点
开始时只用了 spfa,求最短路的数量时会有累计更新(第一次用 x x x 累加了 y y y,后面 x x x 如果发生更新,可能会再次累加 y y y ),使求出的数量多于实际数量。后增加了dfs,感觉时间复杂度有点大。所以最终使用了dijkstra.
code
/*
2020-7-5 11:23:34
nero
没说边权范围,是否路径和超过int,是否有负边权
没说有没有重边
*/
#include <bits/stdc++.h>
using namespace std;
#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair<int,int>
typedef long long ll;
typedef unsigned long long ull;
const int MAXN = 505;
const ll Mod = 1e9+7;
int n, m, C1, C2;
bool vis[MAXN];
int teams[MAXN],f[MAXN],cnt[MAXN],tms[MAXN];
vector<int>v[MAXN],w[MAXN];
queue<int>q;
void spfa(int s) {
q.push(s);
f[s] = 0;
cnt[s] = 1;
vis[s] = 1;
tms[s] = teams[s];
while(!q.empty()) {
int x = q.front();
q.pop();
for(int i = 0; i < v[x].size(); i++) {
int xx = v[x][i];
int len = f[x]+w[x][i];
if(len < f[xx]) {
// cout << "Yes" << endl;
cnt[xx] = cnt[x];
f[xx] = len;
tms[xx] = tms[x] + teams[xx];
if(!vis[xx]) {
vis[xx] = 1;
q.push(xx);
}
}
else if(len == f[xx]) {
// cout << "No" << endl;
cnt[xx]+=cnt[x];
if(tms[xx] < tms[x] + teams[xx]) {
tms[xx] = tms[x] + teams[xx];
if(!vis[xx]) {
vis[xx] = 1;
q.push(xx);
}
}
}
// cout << x << "->" << xx << " f=" << f[xx] << " cnt=" << cnt[xx] << " teams=" << tms[xx] << endl;
}
vis[x] = 0;
}
return;
}
int dfs_cnt = 0;
void dfs(int x, int path) {
if(x == C2) {
if(path == f[C2])
dfs_cnt++;
return;
}
if(path > f[C2]) return;
for(int i = 0; i < v[x].size(); i++) {
int xx = v[x][i];
if(!vis[xx] && f[xx] == f[x] + w[x][i]) {
vis[xx] = 1;
dfs(xx, f[xx]);
vis[xx] = 0;
}
}
}
int main() {
cin >> n >> m >> C1 >> C2;
for(int i = 0; i < n; i++) {
cin >> teams[i];
f[i] = iINF;
}
int x, y,xy;
for(int i = 0; i < m; i++) {
cin >> x >> y >> xy;
v[x].push_back(y);
w[x].push_back(xy);
v[y].push_back(x);
w[y].push_back(xy);
}
spfa(C1);
memset(vis,0,sizeof(vis));
vis[C1] = 1;
dfs(C1,0);
cout << dfs_cnt << " " << tms[C2] << endl;
return 0;
}
/*
spfa求路径数量在这个样例中是错误的,可以验证
2 5 1 0
1 2
0 1 1
0 1 2
0 1 3
0 1 4
1 0 2
*/
方法二 dijkstra
思路
因为dijkstra每次用一个点更新其它点之后,这个点就不会再被用到,避免了多次更新造成的错误累加。
code
/*
2020-7-5 11:29:08
nero
没说边权范围,是否路径和超过int,是否有负边权
没说有没有重边
*/
#include <bits/stdc++.h>
using namespace std;
#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair<int,int>
typedef long long ll;
typedef unsigned long long ull;
const int MAXN = 505;
const ll Mod = 1e9+7;
int n, m, C1, C2;
bool vis[MAXN];
int teams[MAXN],dis[MAXN],cnt[MAXN],tms[MAXN];
vector<int>v[MAXN],w[MAXN];
void dijkstra(int s) {
for(int i = 0; i < v[s].size(); i++) {
dis[v[s][i]] = w[s][i];
}
dis[s] = 0;
cnt[s] = 1;
tms[s] = teams[s];
int Min, p;
for(int i = 0; i < n; i++) {
Min = iINF;
for(int j = 0; j < n; j++) {
if(!vis[j] && dis[j] < Min) {
p = j;
Min = dis[j];
}
}
vis[p] = 1;
for(int j = 0; j < v[p].size(); j++) {
int xx = v[p][j];
if(!vis[xx] && dis[xx] > dis[p] + w[p][j]) {
dis[xx] = dis[p] + w[p][j];
cnt[xx] = cnt[p];
tms[xx] = tms[p] + teams[xx];
}
else if(!vis[xx] && dis[xx] == dis[p] + w[p][j]) {
cnt[xx] += cnt[p];
if(tms[xx] < tms[p] + teams[xx]) {
tms[xx] = tms[p] + teams[xx];
}
}
}
}
return;
}
int main() {
cin >> n >> m >> C1 >> C2;
for(int i = 0; i < n; i++) {
cin >> teams[i];
dis[i] = iINF;
}
int x, y,xy;
for(int i = 0; i < m; i++) {
cin >> x >> y >> xy;
v[x].push_back(y);
w[x].push_back(xy);
v[y].push_back(x);
w[y].push_back(xy);
}
dijkstra(C1);
cout << cnt[C2] << " " << tms[C2] << endl;
return 0;
}
都0202年了我还只会用spfa