POJ 3662 Telephone Lines 二分,最小化第k大的数

一、题目大意

我们有n个点,p条边,最小化从1到n之间的路径的第k+1大的数(当路径不超过k时就是0)

二、解题思路

我们首先用dijkstra过一遍,判断从1能不能到n,不能直接输出-1结束。

1能到达n的话,就对二分第k+1大的边进行二分,left选-1,right选最大的边的长度+1(这里我left一开始选取的时最小边-1,后来发现当k比较大时结果可能是0)

二分的依据如下

cpp 复制代码
设二分的值为mid
记录从1到n的路径中必走的大于mid的值的数量
如果超过了k,那么放大mid
如果小于等于k,那么缩小mid,同时记录

这样不断循环,直到找到一个临界值limit
当mid=limit时,大于mid的边小于等于k个
当mid=limit-1时,大于mid的边超过k个
那么limit一定就是第k+1大的边

输出最后一个(大于mid的边数小于等于k的)mid即可

三、代码

cpp 复制代码
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef pair<int, int> P;
vector<P> edges[1007];
bool used[1007];
int n, p, k, d[1007], inf = 0x3f3f3f3f, maxt = 0;
void input()
{
    int from, to, cost;
    scanf("%d%d%d", &n, &p, &k);
    for (int i = 0; i < p; i++)
    {
        scanf("%d%d%d", &from, &to, &cost);
        edges[from - 1].push_back(P(cost, to - 1));
        edges[to - 1].push_back(P(cost, from - 1));
        maxt = max(cost, maxt);
    }
}
bool judgeByDijkstra(int mid)
{
    for (int i = 0; i < n; i++)
    {
        d[i] = inf;
        used[i] = false;
    }
    d[0] = 0;
    priority_queue<P, vector<P>, greater<P>> que;
    que.push(P(d[0], 0));
    while (!que.empty())
    {
        P current = que.top();
        que.pop();
        if (used[current.second] || current.first > d[current.second])
        {
            continue;
        }
        used[current.second] = true;
        for (int i = 0; i < edges[current.second].size(); i++)
        {
            P toEdge = edges[current.second][i];
            int relativeEdge = toEdge.first > mid ? 1 : 0;
            if (d[current.second] + relativeEdge < d[toEdge.second])
            {
                d[toEdge.second] = d[current.second] + relativeEdge;
                que.push(P(d[toEdge.second], toEdge.second));
            }
        }
    }
    return d[n - 1] <= k;
}
void binarySearch()
{
    int left = -1, right = maxt + 1;
    while (left + 1 < right)
    {
        int mid = (left + right) / 2;
        if (judgeByDijkstra(mid))
        {
            right = mid;
        }
        else
        {
            left = mid;
        }
    }
    printf("%d\n", right);
}
bool judgeIfCanGet()
{
    for (int i = 0; i < n; i++)
    {
        d[i] = inf;
        used[i] = false;
    }
    d[0] = 0;
    priority_queue<P, vector<P>, greater<P>> que;
    que.push(P(d[0], 0));
    while (!que.empty())
    {
        P current = que.top();
        que.pop();
        if (used[current.second] || current.first > d[current.second])
        {
            continue;
        }
        used[current.second] = true;
        for (int i = 0; i < edges[current.second].size(); i++)
        {
            P toEdge = edges[current.second][i];
            if (d[current.second] + toEdge.first < d[toEdge.second])
            {
                d[toEdge.second] = d[current.second] + toEdge.first;
                que.push(P(d[toEdge.second], toEdge.second));
            }
        }
    }
    return d[n - 1] != inf;
}
int main()
{
    input();
    if (!judgeIfCanGet())
    {
        printf("-1\n");
    }
    else
    {
        binarySearch();
    }
    return 0;
}
相关推荐
fie88892 小时前
NSCT(非下采样轮廓波变换)的分解和重建程序
算法
晨晖23 小时前
单链表逆转,c语言
c语言·数据结构·算法
im_AMBER4 小时前
Leetcode 78 识别数组中的最大异常值 | 镜像对之间最小绝对距离
笔记·学习·算法·leetcode
鼾声鼾语5 小时前
matlab的ros2发布的消息,局域网内其他设备收不到情况吗?但是matlab可以订阅其他局域网的ros2发布的消息(问题总结)
开发语言·人工智能·深度学习·算法·matlab·isaaclab
LYFlied5 小时前
【每日算法】LeetCode 25. K 个一组翻转链表
算法·leetcode·链表
Swizard5 小时前
别再迷信“准确率”了!一文读懂 AI 图像分割的黄金标尺 —— Dice 系数
python·算法·训练
s09071365 小时前
紧凑型3D成像声纳实现路径
算法·3d·声呐·前视多波束
可爱的小小小狼5 小时前
算法:二叉树遍历
算法
d111111111d6 小时前
在STM32函数指针是什么,怎么使用还有典型应用场景。
笔记·stm32·单片机·嵌入式硬件·学习·算法
AI科技星7 小时前
质量定义方程常数k = 4π m_p的来源、推导与意义
服务器·数据结构·人工智能·科技·算法·机器学习·生活