1003 Emergency (25 分)
今天分享的是PAT甲级的一道小题,是一道经典的回溯剪枝的问题
简单翻译:
给你一个无向图,一共N个节点M条边,每个节点对应一个权重,节点之间的边有路径的长度,求从其中的c1节点到c2节点一共有多少种最短路径,这些路径所经历的节点的最大权重是多少。
思路:
最开始的思路是Dijkstra,后来发现没有必要使用Dijkstra,就是一个回溯+剪枝的应用。
从根节点出发,有路径就开始走,并维护当前的状态,如果某个点没有走过,并且与当前的点存在连线的话,就走那个节点
如果当前节点已经是目的节点了,那么就开始维护需要的值
- 判断是不是最短路径
- 如果比当前最短的还要短,就更新当前最短路径的条数为1,并且权重直接赋值为当前的权重
- 如果和当前的路径一样短,就将最短路径的条数 + 1,并且维护当前的权重,取最大值。
- 相反则直接忽略。
这样通过暴力的遍历+部分剪枝,就可以通过这道题,算是一道经典的问题了。
c++代码:
#include"bits/stdc++.h"
#define all(x) x.begin(),x.end()
#define len(x) x.size()
#define INF (1e9)
#define vi vector<int>
#define ll long long
#define db double
#define vvi vector<vector<int>>
#define pb(x) push_back(x);
using namespace std;
vvi grid(501, vi(501, 0));
vi vis(501, 0);
vi num(501, 0);
int n, m, c1, c2;
int cnt = 0, people = -INF, minRoad = INF;
void dfs(int now, int peo, int road) {
if (now == c2) {
if (road == minRoad) {
minRoad = road;
people = max(people, peo);
cnt++;
}
if (road < minRoad) {
minRoad = road;
people = peo;
cnt = 1;
}
return;
}
for (int i = 0; i < n; i++) {
if (grid[now][i] > 0 && vis[i] == 0) {
vis[i] = 1;
dfs(i, peo + num[i], road + grid[now][i]);
vis[i] = 0;
}
}
}
int main() {
cin >> n >> m >> c1 >> c2;
for (int i = 0; i < n; i++) {
cin >> num[i];
}
for (int i = 0; i < m; i++) {
int temp1, temp2, temp3;
cin >> temp1 >> temp2 >> temp3;
grid[temp1][temp2] = temp3;
grid[temp2][temp1] = temp3;
}
dfs(c1, num[c1], 0);
cout << cnt << " " << people;
return 0;
}