PAT -- 甲级1003(1003 Emergency)

版权声明:Please work hard for your dreams. https://blog.csdn.net/calculate23/article/details/89185335

1003 Emergency (25 分)

As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

Input Specification:

Each input file contains one test case. For each test case, the first line contains 4 positive integers: NNN (≤500\le 500500) - the number of cities (and the cities are numbered from 0 to N−1N-1N1), MMM - the number of roads, C1C_1C1 and C2C_2C2 - the cities that you are currently in and that you must save, respectively. The next line contains NNN integers, where the iii-th integer is the number of rescue teams in the iii-th city. Then MMM lines follow, each describes a road with three integers c1c_1c1, c2c_2c2 and LLL, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C1C_1C1 to C2C_2C2.

Output Specification:

For each test case, print in one line two numbers: the number of different shortest paths between C1C_1C1 and C2C_2C2, and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.

Sample Input:

5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1

Sample Output:

2 4

先给4个数分别代表:点数,边数,起点终点。之后给n个点的权值以及m条边的边权,求从起点到终点在边权和最小的前提下输出最短路的路径数以及这条最短路的点权和的最大值。

思路
首先dijkstra可以记录路径,只需要一个前缀点的表记录就成功,但这里最短路不止要记录一条所以要用一个向量来保存…另外一种做法就是直接维护边数以及第二维的权值的前缀和。

  • 当最短路更新时,除了要更新到达点的路径长度还要更新点权前缀和以及最短路的数量
  • 当找到另外一条最短路时要更新路径数,即cnt[v] += cnt[u](因为本来已经有一条到达该点了,现在又多了u那点的一条路,但到达u的不一定只有一条,实际上是cnt[u]条),然后就是更新第二维权值的前缀和(我这种写法是到达该点后才加上该点的权,所以在外部记得每次要加上node [u])
  • 注意题目有个很大的坑点,就是目的地就是起点。最短路就是1条,权值前缀和就是node[start]

Code

#include <bits/stdc++.h>

using namespace std;
const int maxn = (int)5e2+5;
const int inf = 0x3f3f3f3f;

int n, m, start, goal;
int Martix[maxn][maxn], cost[maxn];
int node[maxn], quan[maxn],cnt[maxn];
bool vis[maxn];

void Init () {
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
      if (i == j) Martix[i][j] = 0;
      else Martix[i][j] = inf;
    }
    cost[i] = inf;
  }
  for (int i = 1; i <= n; i++) {
    cin >> node[i];
  }
  int a,b,c;
  for (int i = 1; i <= m; i++) {
    cin >> a >> b >> c;
    Martix[a+1][b+1] = Martix[b+1][a+1] = c;
  }
}

void Dijkstra () {
  memset(vis, false, sizeof(vis));
  for (int i = 1; i <= n; i++) {
    cost[i] = Martix[start][i];
    if (cost[i] != inf) {
      quan[i] = node[start];
      cnt[i] = 1;
    } else { //达不到
      quan[i] = 0;
      cnt[i] = 0;
    }
  }
  vis[start] = true;
  int u,v;
  while (true) {
    u = -1;
    for (v = 1; v <= n; v++) {
      if (!vis[v] && (u == -1 || cost[u] > cost[v])) {
        u = v;
      }
    }
    if (u == -1) {
      break;
    }
    vis[u] = true;
    quan[u] += node[u];  //到达该点要把该点的权值+到到达u的前缀和中
    for (v = 1; v <= n; v++) {
      if (!vis[v] && cost[v] > cost[u] + Martix[u][v]) {
        cost[v] = cost[u] + Martix[u][v];
        quan[v] = quan[u]; //找到最短路,更新第二个权值
        cnt[v] = cnt[u];
      } else if (!vis[v] && cost[v] == cost[u] + Martix[u][v]) {
        quan[v] = max(quan[v], quan[u]); //更新到达v点前的点权值前缀和的最大值
        cnt[v] += cnt[u];
      }
    }
  }
}

int main() {
  cin >> n >> m >> start >> goal;
  start++;
  goal++;
  Init();
  Dijkstra();
  cout << cnt[goal] << " " << quan[goal] << endl;
  return 0;
}

猜你喜欢

转载自blog.csdn.net/calculate23/article/details/89185335