Description
你来到一个迷宫前。该迷宫由若干个房间组成,每个房间都有一个得分,第一次进入这个房间,你就可以得到这个分数。还有若干双向道路连结这些房间,你沿着这些道路从一个房间走到另外一个房间需要一些时间。游戏规定了你的起点和终点房间,你首要目标是从起点尽快到达终点,在满足首要目标的前提下,使得你的得分总和尽可能大。现在问题来了,给定房间、道路、分数、起点和终点等全部信息,你能计算在尽快离开迷宫的前提下,你的最大得分是多少么?
Input
第一行4个整数n (<=500), m, start, end。n表示房间的个数,房间编号从0到(n - 1),m表示道路数,任意两个房间之间最多只有一条道路,start和end表示起点和终点房间的编号。
第二行包含n个空格分隔的正整数(不超过600),表示进入每个房间你的得分。
再接下来m行,每行3个空格分隔的整数x, y, z (0 < z <= 200)表示道路,表示从房间x到房间y(双向)的道路,注意,最多只有一条道路连结两个房间, 你需要的时间为z。
输入保证从start到end至少有一条路径。
Output
一行,两个空格分隔的整数,第一个表示你最少需要的时间,第二个表示你在最少时间前提下可以获得的最大得分。
Input示例
3 2 0 2
1 2 3
0 1 10
1 2 11
Output示例
21 6
做法:
一种朴素的想法就是最短路咯,毕竟第一问要求嘛,然后我们发现,这种朴素的想法稍加修改就可一AC呀,其实就是在更新最短路的时候顺便更新积分。
代码如下:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#define N 400000
using namespace std;
struct arr
{
int t,n,w;
}f[N];
int str[N], ls[N], e, s, t, n, m, d[N], g[N], a[N];
bool v[N];
int read()
{
int s = 0, p = 1;
char ch = getchar();
while (ch < '0' || ch > '9' && ch != '-') ch = getchar();
if (ch == '-') p = -1, ch = getchar();
while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * p;
}
int add(int x, int y, int z)
{
f[++e].t = y;
f[e].n = ls[x];
ls[x] = e;
f[e].w = z;
}
int spfa()
{
int head = 0, tail = 1;
str[1] = s;
v[s] = 1;
for (int i = 0; i <= n; i++)
d[i] = 0x7f7f7f7f;
d[s] = 0;
g[s] = a[s];
while (head < tail)
{
head += 1;
int p = str[head];
for (int i = ls[p]; i; i = f[i].n)
{
if (d[p] + f[i].w < d[f[i].t])
{
d[f[i].t] = d[p] + f[i].w;
g[f[i].t] = g[p] + a[f[i].t];
if (! v[f[i].t])
{
v[f[i].t] = 1;
tail += 1;
str[tail] = f[i].t;
}
}
else if (d[p] + f[i].w == d[f[i].t])
{
g[f[i].t] = max(g[p] + a[f[i].t], g[f[i].t]);
}
}
v[p] = 0;
}
}
int main()
{
n = read(), m = read(), s = read(), t = read();
int x, y, z;
for (int i = 0; i <= n - 1; i++)
a[i] = read();
for (int i = 1; i <= m; i++)
{
x = read();
y = read();
z = read();
add(x, y, z);
add(y, x, z);
}
spfa();
printf("%d ", d[t]);
printf("%d", g[t]);
}