• 《算法竞赛进阶指南》,USACO2008 通信线路


    在郊区有 NN 座通信基站,PP 条 双向 电缆,第 ii 条电缆连接基站 AiAi 和 BiBi。

    特别地,11 号基站是通信公司的总站,NN 号基站位于一座农场中。

    现在,农场主希望对通信线路进行升级,其中升级第 ii 条电缆需要花费 LiLi。

    电话公司正在举行优惠活动。

    农产主可以指定一条从 11 号基站到 NN 号基站的路径,并指定路径上不超过 KK 条电缆,由电话公司免费提供升级服务。

    农场主只需要支付在该路径上剩余的电缆中,升级价格最贵的那条电缆的花费即可。

    求至少用多少钱可以完成升级。

    输入格式

    第 11 行:三个整数 N,P,KN,P,K。

    第 2..P+12..P+1 行:第 i+1i+1 行包含三个整数 Ai,Bi,LiAi,Bi,Li。

    输出格式

    包含一个整数表示最少花费。

    若 11 号基站与 NN 号基站之间不存在路径,则输出 −1−1。

    数据范围

    0≤K 1≤P≤100001≤P≤10000,
    1≤Li≤10000001≤Li≤1000000

    输入样例:

    1. 5 7 1
    2. 1 2 5
    3. 3 1 4
    4. 2 4 8
    5. 3 2 3
    6. 5 2 9
    7. 3 4 7
    8. 4 5 6

    输出样例:

    4

     

    定义在[0, 1000001]性质如下
    {
        对于区间的一个点x,找出最少经过的长度大于x的边的数量是否小于等于k
        进而二分出最少经过的长度大于x的边的数量大于k的最小值;
        问题一:如何判断是否可以二分:
        {
            假设答案为ans, 则他的定义为该最短路上长度大于ans的边的数量正好小于等于k
            假定任意一个数x > ans 则该最短路上长度大于ans的边的数量仍然是小于等于k的
            若x < ans 则该最短路上长度大于ans的边的数量仍然是大于k的(因为至少包含了ans);
            所以可以二分
        }
        
        问题二:为何找的是最少经过的长度呢?
        {
            保证答案最小,假设该条路总共存在i条边,若选择最少经过的点
            则k可能大于i则答案为0,若此时不选择最少经过的长度答案可能大于0
        }
        
        问题三:为何不是从[1, 1000000]枚举而是从[0, 1000001]枚举呢?
        {
            当所选则的长度大于x的边的数量全都小于k是答案是0;
            当无解时长度输出应该是无法到达,即check函数一直是false, 边长一直在扩大,若
            边界为1000000则最终答案为1000000,但为1000000也可能是答案,所以要定义
            1000001表示无解
        }
    }

    求1到N至少经过几条长度大于x的边。
    可以将所有边分类,长度小于等于x的边权定为0放入队头
    长度大于x的边权定位1放入队尾 

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. const int N = 1010, M = 20010;
    7. int n, m, k;
    8. bool st[N];
    9. int dist[N];
    10. int h[N], e[M], ne[M], w[M], idx;
    11. void add(int a, int b, int c)
    12. {
    13. e[idx] = b;
    14. w[idx] = c;
    15. ne[idx] = h[a];
    16. h[a] = idx;
    17. idx ++ ;
    18. }
    19. bool check(int bound)
    20. {
    21. memset(st, false, sizeof st);
    22. memset(dist, 0x3f, sizeof dist);
    23. deque<int> q;
    24. dist[1] = 0;
    25. q.push_back(1);
    26. while (q.size())
    27. {
    28. auto t = q.front();
    29. q.pop_front();
    30. if (st[t]) continue;
    31. st[t] = true;
    32. for (int i = h[t]; i != -1; i = ne[i])
    33. {
    34. int j = e[i], v = w[i] > bound;
    35. if (dist[j] > dist[t] + v)
    36. {
    37. dist[j] = dist[t] + v;
    38. if (!v) q.push_front(j);
    39. else q.push_back(j);
    40. }
    41. }
    42. }
    43. return dist[n] <= k;
    44. }
    45. int main()
    46. {
    47. cin >> n >> m >> k;
    48. memset(h, -1, sizeof h);
    49. while (m -- )
    50. {
    51. int a, b, c;
    52. scanf("%d %d %d", &a, &b, &c);
    53. add(a, b, c), add(b, a, c);
    54. }
    55. int l = 0, r = 1000001;
    56. while (l < r)//最终的答案为除去k条边之外的最小值不懂得建议去看两个二分模板:
    57. { //https://blog.csdn.net/qq_61935738/article/details/125466959
    58. int mid = l + r >> 1;
    59. if (check(mid)) r = mid;
    60. else l = mid + 1;
    61. }
    62. if (r == 1000001) r = -1;
    63. cout << r << endl;
    64. return 0;
    65. }

  • 相关阅读:
    动漫制作技巧如何制作动漫视频
    深入源码剖析String类为什么不可变?(还不明白就来打我)
    基于matlab仿真多普勒效应及其影响(附源码)
    Docker私库
    APISIX安装与灰度、蓝绿发布
    bwapp下载安装
    【RocketMQ】消息的存储总结
    遨博机械臂——MoveIt设置助手机械臂配置
    netsh interface portproxy端口转发,从本地端口到本地端口不起作用的解决办法
    nn.MultiheadAttention详解 -- forward()中维度、计算方式
  • 原文地址:https://blog.csdn.net/qq_61935738/article/details/126281497