专注 效率 记忆
预习 笔记 复习 做题
欢迎观看我的博客,如有问题交流,欢迎评论区留言,一定尽快回复!(大家可以去看我的专栏,是所有文章的目录)
文章字体风格:
红色文字表示:重难点★✔
蓝色文字表示:思路以及想法★✔
如果大家觉得有帮助的话,感谢大家帮忙
点赞!收藏!转发!
截取重要部分,看完全篇即懂
利用二分遍历最终答案
也就是遍历
第k+1条边的最小值
每次二分一个值
然后让图中所有大于该值的边为1
所有小于该值的边 为0
然后从起到走到终点
看最小距离(也就是大于该值的边数)
如果边数大于K了,那么以该值为最终答案,一定会使得最终答案变小,所以左区间右移(下次遍历更大的值)
如果边数等于K,那么该值为最终答案或许合适(右区间左移,下次遍历更小的值)
如果边数小于K,那么该值可能使得最终答案变大(也就是大于最终答案)那么也右区间左移动(下次遍历更小的值)
起点到终点 走哪条路径使得(路径长度排序后) 第k+1条边最小
- 利用二分遍历最终答案
- 补充问题:0 1边权,求最小距离
本题题意:
起点到终点 走哪条路径使得(路径长度排序后从大到小) 第k+1条边最小
一种想法就是
遍历所有
起点到终点的路径
求出第k+1边
这样时间复杂度太大
优化:
二分
利用二分遍历最终答案
也就是遍历
第k+1条边的最小值
每次二分一个值
然后让图中所有大于该值的边为1
所有小于该值的边 为0
然后从起到走到终点
看最小距离(也就是大于该值的边数)
如果边数大于K了,那么以该值为最终答案,一定会使得最终答案变小,所以左区间右移(下次遍历更大的值)
如果边数等于K,那么该值为最终答案或许合适(右区间左移,下次遍历更小的值)
如果边数小于K,那么该值可能使得最终答案变大(也就是大于最终答案)那么也右区间左移动(下次遍历更小的值)
补充问题:0 1边权,求最小距离
可以用双端队列
双端队列求最小距离
#include <cstring>
#include <iostream>
#include <algorithm>
#include <deque>using namespace std;const int N = 1010, M = 20010;int n, m, k;
int h[N], e[M], w[M], ne[M], idx;
int dist[N];
deque<int> q;
bool st[N];void add(int a, int b, int c)
{e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}bool check(int bound)
{memset(dist, 0x3f, sizeof dist);memset(st, 0, sizeof st);q.push_back(1);dist[1] = 0;while (q.size()){int t = q.front();q.pop_front();if (st[t]) continue;st[t] = true;for (int i = h[t]; ~i; i = ne[i]){int j = e[i], x = w[i] > bound;if (dist[j] > dist[t] + x){dist[j] = dist[t] + x;if (!x) q.push_front(j);else q.push_back(j);}}}return dist[n] <= k;
}int main()
{cin >> n >> m >> k;memset(h, -1, sizeof h);while (m -- ){int a, b, c;cin >> a >> b >> c;add(a, b, c), add(b, a, c);}int l = 0, r = 1e6 + 1;while (l < r){int mid = l + r >> 1;if (check(mid)) r = mid;else l = mid + 1;}if (r == 1e6 + 1) cout << -1 << endl;else cout << r << endl;return 0;
}