题目大意:
一个有向带权图,求源点到其他顶点的最短路径和该顶点值的和的最小值,典型的单元最短路径问题。不过每个顶点都有一个等级,源点到任意一个顶点最短路径上的任意两个顶点(包括源点和该顶点)的等级差不能超过给定的值。
解题思路:
我做这道题的经历:
1、题意理解错误,错认为只要满足相邻的结点的等级差在给定范围内就可以。
2、在dijkstra算法中记录每个结点的父亲结点,在讨论一个结点时,根据父亲结点不断往上遍历直到源点,如果该结点与往上遍历的所有父亲结点的等级差都在指定范围内,则更新该结点。(这用方法对有的路径不能考虑进去)
3、深搜,深搜算法写的不好,出现MLE
4、枚举一定范围内的点,dijkstra算法中只考虑在枚举范围内的顶点。(过题)
代码:
#include <cstdio>
#include <cstring>
#define M 125
const int INF = (1<<30)-1;
int m, n;
int p, l, x, t, v;
int value[M], charge[M][M];
int layer[M], low, high;
int vis[M], lowcost[M], path[M];
void dijkstra(int beg) {
int i, j, minc;
memset(vis, 0, sizeof(vis));
vis[beg] = 1;
for(i=0; i<n; i++) { //在初始化lowcost[]数组的时候要判断其等级是否在指定范围,在这WA了多次
if(layer[i]>=low && layer[i]<=high)
lowcost[i] = charge[beg][i];
else lowcost[i] = INF;
}
lowcost[beg] = 0;
int pre = beg;
for(int i=1; i<n; i++) {
minc = INF;
for(j=0; j<n; j++) {
if(vis[j] == 0 && lowcost[pre]+charge[pre][j]<lowcost[j] &&
layer[j] >=low && layer[j] <= high) { //值考虑在枚举范围内的点
lowcost[j] = lowcost[pre] + charge[pre][j];
}
}
for(j=0; j<n; j++) {
if(vis[j] == 0 && lowcost[j] < minc && layer[j]>=low && layer[j]<=high) { //同样只需要考虑在
minc = lowcost[j]; pre = j; //枚举范围之内的点
}
}
vis[pre] = 1;
}
}
void init() {
for(int i=0; i<n; i++) {
for(int j=0; j<n; j++) {
if(i == j) charge[i][j] = 0;
else
charge[i][j] = INF;
}
}
}
int main() {
while(~scanf("%d%d", &m, &n)) {
init();
for(int i=0; i<n; i++) {
scanf("%d%d%d", &p, &l, &x);
value[i] = p; layer[i] = l;
for(int j=0; j<x; j++) {
scanf("%d%d", &t, &v);
charge[i][t-1] = v;
}
}
int ans = INF;
for(low = layer[0]-m; low<=layer[0]; low++) { //枚举等级范围,对于每个范围,用dijkstra算法
high = low + m; //求出最优值。
dijkstra(0);
for(int i=0; i<n; i++) {
if(lowcost[i] + value[i] < ans) {
ans = lowcost[i] + value[i];
}
}
}
printf("%d\n", ans);
}
return 0;
}