传送门
// 题意: 给定(n, m)无向图, 每条路上面除了边权还有一个高度, 如果高度为-1那么说明这个无限高. 然后给定一个起点和终点和一个限制高度, 问从起点到终点不超过限制高度的最高高度是多少, 并输出在此高度下的最短路径是多少, 如果不能到达就输出”不能到达”.
// 思路: 很明显的, 每条路上面除了一个边权值还有一个关键字是高度, 那么像这种要求每条边上的某个关键字最大或最小或多少的, 一般都是二分, 所以我们直接二分高度, 然后跑最短路验证ans即可.
AC Code
const int maxn = 1e3+5;
int cas=1;
int cnt, head[maxn];
struct node
{
int to, next, h, w;
bool operator < (const node& a) const {
return w > a.w;
}
} e[maxn*maxn];
void add(int u, int v,int h ,int w) {
e[cnt] = (node){v,head[u], h, w};
head[u] = cnt++;
}
void init() {
cnt = 0;
memset(head, -1, sizeof(head));
}
bool vis[maxn];
int dis[maxn];
int dij(int st,int ed, int flag)
{
priority_queue<node> q;
Fill(dis,inf); Fill(vis,0);
dis[st] = 0;
q.push((node){st, 0, 0, 0});
while (!q.empty()) {
node u = q.top();
q.pop();
if(vis[u.to]) continue;
vis[u.to] = 1;
for (int i = head[u.to]; ~i; i = e[i].next) {
node k = e[i];
if (k.h != -1 && k.h < flag) continue;
if (dis[k.to] > dis[u.to] + k.w) {
dis[k.to] = dis[u.to] + k.w;
q.push((node){k.to, 0, 0, dis[k.to]});
}
}
}
if (dis[ed] == inf) return -1;
return dis[ed];
}
void solve() {
int n, m, read = -1;
while(1) {
if (read == - 1) scanf("%d%d", &n, &m);
if (n + m == 0) break;
init();
for (int i = 1 ; i <= m ; i ++) {
int u ,v , h ,w;
scanf("%d%d%d%d", &u, &v, &h, &w);
add(u, v, h, w);
add(v, u, h, w);
}
int st, ed, lim;
scanf("%d%d%d", &st, &ed, &lim);
int l = 1, r = lim, mid , ans1 = -1, ans2;
while(r >= l) {
mid = (l + r) >> 1;
int tmp = dij(st, ed, mid);
if (tmp != -1) {
l = mid + 1;
ans1 = mid;
ans2 = tmp;
}
else r = mid-1;
}
printf("Case %d:\n", cas++);
if (ans1 == -1) printf("cannot reach destination\n");
else {
printf("maximum height = %d\n", ans1);
printf("length of shortest route = %d\n", ans2);
}
scanf("%d%d", &n, &m);
if (n + m != 0) printf("\n");
read = 1;
}
}