题意:一个公司运送货物。道路和货车自身都有限高。要求在限高尽量高的情况下选择最短的道路。
思路:单源最短路经问题,用两次Dijkstra算法,第一次求出出发地到目的地最大限高,第二次在求出的最大限高基础上求最短路。
Dijkstra求最大限高的思路:我们需要将Dijkstra变形一下。对于一条路径来说,它的最大限高是这条路上每段道路的限高和货车限高的最小值。如果从a到b有多条路径,则从a到b的最大限高是这多条路径的最大限高的最大值,见下图。简单来说就是取一条路径上的最小值,不同路径之间的最大值。
原先Dijkstra的贪心部分是每次选一个距离源点最短的点,但这里我们需要每次选一个到源点限高值最大的点,因为我们需要的贪心改变了,我们现在需要的是最大的限高。
Dijkstra求最大限高思路的描述性证明:当从源点到各个点的最大限高都求出来后,相当于产生了一个生成树。和Dijkstra算法的描述性证明类似,当我们每次选一个最大限高的点,就有一条生成树的边被确定了下来。
代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<stack>
#include<queue>
#include<utility>
#include<vector>
#include<cmath>
#include<set>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 1010;
const int INF = 0x3f3f3f3f;
struct NodeH{
int v,w;
NodeH(){}
NodeH(int a, int b):v(a),w(b){}
bool operator < (const NodeH& n)const{
return w < n.w;
}
};
struct NodeD{
int v,w;
NodeD(){}
NodeD(int a, int b):v(a),w(b){}
bool operator < (const NodeD& n)const{
return w > n.w;
}
};
int C, R;
int start,endd,truckh;
int H[MAXN][MAXN];
int G[MAXN][MAXN];
int h[MAXN];
int d[MAXN];
bool vis[MAXN];
void DijkstraH(int s)//求出最大限高。大概思路是从a到b的一条路径的最大限高是这条路径上道路的限高和货车限高的最小值。如果从 { //a到b有多条路径,则从a到b的最大限高是这多条路径最大限高的最大值。
memset(h, -1, sizeof(h));
memset(vis, false, sizeof(vis));
h[s] = truckh;
priority_queue<NodeH> que;
que.push(NodeH(s, truckh));
while(!que.empty()){
NodeH tmp = que.top(); que.pop();
if(vis[tmp.v]) continue;
vis[tmp.v] = true;
for(int i=1; i<=C; i++){
if(!vis[i] && h[i]<min(h[tmp.v],H[tmp.v][i])){ //h[i]代表原先的一条路径的最大限高,
h[i] = min(h[tmp.v],H[tmp.v][i]); //min(h[tmp.v],H[tmp.v][i])代表新路径的最大限
que.push(NodeH(i, h[i])); //高。即取一条路径上的最小值,不同路径之间的最大值
}
}
}
}
void DijkstraD(int s)
{
memset(vis, false, sizeof(vis));
for(int i=1; i<=C; i++) d[i] = INF;
d[s] = 0;
priority_queue<NodeD> que;
que.push(NodeD(s, 0));
while(!que.empty()){
NodeD tmp = que.top(); que.pop();
vis[tmp.v] = true;
for(int i=1; i<=C; i++){
if(!vis[i] && H[tmp.v][i]>=h[endd] && G[tmp.v][i]<INF && d[tmp.v]<INF && d[i]>d[tmp.v]+G[tmp.v][i]){ //H[tmp.v][i]>=h[endd] 表示道路限高低于所求出的最大限高时不能从这条路走
d[i] = d[tmp.v]+G[tmp.v][i];
que.push(NodeD(i, d[i]));
}
}
}
}
void Init()
{
memset(H, -1, sizeof(H));
for(int i=0; i<MAXN; i++){
for(int j=0; j<MAXN; j++){
G[i][j] = INF;
}
}
}
int main()
{
//freopen("in.txt", "r", stdin);
int kase = 1;
while(scanf("%d%d", &C, &R)==2 && C!=0 && R!=0){
Init();
while(R--){
int a,b,c,l;
scanf("%d%d%d%d", &a, &b, &c, &l);
if(c == -1) H[a][b] = H[b][a] = INF;
else H[a][b] = H[b][a] = c;
G[a][b] = G[b][a] = l;
}
scanf("%d%d%d", &start, &endd, &truckh);
DijkstraH(start);
if(kase != 1) printf("\n");
printf("Case %d:\n", kase++);
if(h[endd] == -1){
printf("cannot reach destination\n");
}
else{
DijkstraD(start);
printf("maximum height = %d\n", h[endd]);
printf("length of shortest route = %d\n", d[endd]);
}
}
return 0;
}