版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SSL_hzb/article/details/84667212
题意
给出一个图,求出其中一条从点 到点 的路径,在上面选掉 条边,使得剩下的边中最大的最小。
思路
这个题其实是求出一条 到 的路径中使得第 的边最小。
解法一:
首先看到字样“最大的最小”,我们可以感觉这个题可以用二分,然后细读一下发现答案满足单调性。
当我们二分出一个
,可以求出这个图中从
到
的路径中大于
的边的个数,如果个数超过了
,说明答案不可行。
求出这个边的个数我们只用把超过
的边权记为
,然后利用
或双端队列
的方法就可以求出了。
解法二:
可以用动态规划,设
为从
到
中已经选了
条路的最优答案,可得:
表示选
表示不选
其中
表示边的另一个点,
表示权值。
因为没有一个确定的顺序
,我们可以用
来转移,相当于取
就为松弛操作。
代码
解法一:
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
int N, P, K, tot, l, r;
int head[1001], vis[1001], d[1001];
struct node{
int to, v, next;
}e[20001];
void add(int x, int y, int z) {
e[++tot].to = y;
e[tot].v = z;
e[tot].next = head[x];
head[x] = tot;
e[++tot].to = x;
e[tot].v = z;
e[tot].next = head[y];
head[y] = tot;
}
int check(int x) {
deque<int> q;
memset(d, 0, sizeof(d));
memset(vis, 0, sizeof(vis));
q.push_back(1);
vis[1] = 1;
while (q.size()) {
int u = q.front(), v;
q.pop_front();
for (int i = head[u]; i; i = e[i].next) {
v = e[i].to;
if (!vis[v] || d[v] >= d[u] + 1) {
vis[v] = 1;
//双端队列做法可保证每次取出来的点都是最优的
if (e[i].v > x) q.push_back(v), d[v] = d[u] + 1;
else q.push_front(v), d[v] = d[u];
}
}
}
return d[N] <= K && vis[N];
}
int main() {
scanf("%d %d %d", &N, &P, &K);
for (int i = 1, x, y, z; i <= P; i++) {
scanf("%d %d %d", &x, &y, &z);
add(x, y, z);
r = max(r, z);
}
l = 1;
int mid, f = 0;//f记录无解情况
while (l < r) {
mid = (l + r) >> 1;
if (check(mid)) r = mid, f = 1;
else l = mid + 1;
}
printf("%d", f ? r : -1);
}
解法二:
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
int N, P, K, tot;
int head[1001], f[1001][1001], v[1001][1001];
struct node{
int to, v, next;
}e[20001];
void add(int x, int y, int z) {
e[++tot].to = y;
e[tot].v = z;
e[tot].next = head[x];
head[x] = tot;
e[++tot].to = x;
e[tot].v = z;
e[tot].next = head[y];
head[y] = tot;
}
void spfa() {
memset(f, 127 / 3, sizeof(f));
queue< pair<int, int> > q;
q.push(make_pair(1, 0));
v[1][0] = 1;
f[1][0] = 0;
pair<int, int> a;
while (q.size()) {
a = q.front();
q.pop();
v[a.first][a.second] = 0;
for (int i = head[a.first]; i; i = e[i].next) {
if (a.second < K && f[a.first][a.second] < f[e[i].to][a.second + 1]) {//use
f[e[i].to][a.second + 1] = f[a.first][a.second];
if (!v[e[i].to][a.second + 1]) {
v[e[i].to][a.second + 1] = 1;
q.push(make_pair(e[i].to, a.second + 1));
}
}
if (max(e[i].v, f[a.first][a.second]) < f[e[i].to][a.second]) {//not use
f[e[i].to][a.second] = max(e[i].v, f[a.first][a.second]);
if (!v[e[i].to][a.second]) {
v[e[i].to][a.second] = 1;
q.push(make_pair(e[i].to, a.second));
}
}
}
}
}
int main() {
scanf("%d %d %d", &N, &P, &K);
for (int i = 1, x, y, z; i <= P; i++) {
scanf("%d %d %d", &x, &y, &z);
add(x, y, z);
}
spfa();
printf("%d", f[N][K] == 707406378 ? -1 : f[N][K]);
}