题目描述
给定一个图, 可以选着一个1 -> n的路线, 然后可以把这条路上的k个边免费, 然后支付免费后最贵的一条边, 求支付的这条边最小是多少
样例
Sample Input
5 7 1
1 2 5
3 1 4
2 4 8
3 2 3
5 2 9
3 4 7
4 5 6
Sample Output
4
思路
- 二分答案, l = 0, r = 1e6+1
- 因为结果可能是0的, 所以左边界是0, 因为可能存在无解的情况, 所以有边界是1e6+1
- 然后我们把二分答案, 把边权大于答案的设为1, 小于的设为0, dis[n]里面存的就是从1到n大于答案的数量, 我们找到大于答案的数量最多(k)的答案就是最后的结果
- 由于边权只有0和1, 所以我们用到双端队列优化
#include <iostream>
#include <cstring>
#include <algorithm>
#include <deque>
using namespace std;
const int N = 20010;
int e[N], w[N], ne[N], h[1010], len;
int n, m, k;
bool vis[1010];
int dis[1010];
void add(int a, int b, int c)
{
e[len] = b;
w[len] = c;
ne[len] = h[a];
h[a] = len++;
}
bool check(int bound)
{
memset(vis, false, sizeof vis);
memset(dis, 0x3f, sizeof dis);
dis[1] = 0;
deque<int> q;
q.push_back(1);
while(q.size())
{
int x = q.front();
q.pop_front();
if(vis[x]) continue;
vis[x] = true;
for(int i = h[x]; ~i; i = ne[i])
{
int y = e[i];
int c = w[i] > bound;
if(dis[y] > dis[x] + c)
{
dis[y] = dis[x] + c;
if(c == 0)
q.push_front(y);
else q.push_back(y);
}
}
}
return dis[n] <= k;
}
int main()
{
cin >> n >> m >> k;
memset(h, -1, sizeof h);
for(int i = 1; i<= m; i++)
{
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;
}