• 二分,Dijkstra,340. 通信线路


    340. 通信线路 - AcWing题库 

    在郊区有 N 座通信基站,P 条 双向 电缆,第 i 条电缆连接基站 Ai 和 Bi。

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

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

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

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

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

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

    输入格式

    第 1 行:三个整数 N,P,K

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

    输出格式

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

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

    数据范围

    0≤K 1≤P≤10000
    1≤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

     解析:

     本题求的是:最大值的最小值 --> 二分(一般最大值的最小值都是使用二分来做)

     既然要使用二分来做,我们就需要寻找一个能使用二分来求解的性质,对其加以利用。

    性质:从 1 ——N 是否存在一条路径,使得路径中 > mid 的边的个数 <= k 具有二段性。

    因此可以对以上性质加以利用。

    可以知道 >mid 的边应尽可能的少,所以我们可以使用最短路算法进行求解。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. using namespace std;
    16. typedef long long LL;
    17. const int N = 1e3 + 5;
    18. int n, m, k;
    19. vectorint, int>>G[N];
    20. int d[N], v[N];
    21. typedef struct st {
    22. int u, w;
    23. }st;
    24. bool operator>(const st& a, const st& b) {
    25. return a.w > b.w;
    26. }
    27. int dij(int w) {
    28. memset(d, 0x3f3f3f3f, sizeof(d));
    29. memset(v, 0, sizeof(v));
    30. priority_queue, greater>q;
    31. q.push({ 1,0 });
    32. d[1] = 0;
    33. int t;
    34. while (!q.empty()) {
    35. t = q.top().u;
    36. q.pop();
    37. if (v[t])
    38. continue;
    39. v[t] = 1;
    40. for (int i = 0; i < G[t].size(); i++) {
    41. int j = G[t][i].first, dist = G[t][i].second>w?1:0;
    42. if (d[j] > d[t] + dist) {
    43. d[j] = d[t] + dist;
    44. q.push({ j,d[j] });
    45. }
    46. }
    47. }
    48. if (d[n] == 0x3f3f3f3f)
    49. return d[n];
    50. return d[n] <= k;
    51. }
    52. int main() {
    53. cin >> n >> m >> k;
    54. for (int i = 1,a,b,t; i <= m; i++) {
    55. scanf("%d%d%d", &a, &b, &t);
    56. G[a].push_back({ b,t });
    57. G[b].push_back({ a,t });
    58. }
    59. int l = 0, r = 10, mid,ans=0,tt;
    60. while (l<=r) {
    61. mid = l + (r - l) / 2;
    62. tt = dij(mid);
    63. if (tt == 0x3f3f3f3f) {
    64. cout << -1 << endl;
    65. break;
    66. }
    67. if (tt) {
    68. r = mid-1;
    69. }
    70. else {
    71. l = mid+1;
    72. ans = mid;
    73. }
    74. }
    75. if (tt != 0x3f3f3f3f)
    76. cout << ans << endl;
    77. return 0;
    78. }

    由上述分析可知,本题中的实际边权只有 0 和 1 ,因此我们还可以使用双端队列来处理

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. using namespace std;
    18. typedef pair<double, int > PDI;
    19. typedef pair<int, int> PII;
    20. const int N = 1e3+5, M = 2e4 + 5;
    21. int n, p, k;
    22. int h[N], e[M], w[M], ne[M], idx;
    23. int vis[N], d[N];
    24. void add(int a, int b, int c) {
    25. e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
    26. }
    27. int check(int mid) {
    28. memset(vis, 0, sizeof vis);
    29. memset(d, 0x3f, sizeof d);
    30. deque<int>dq;
    31. d[1] = 0;
    32. dq.push_back(1);
    33. while (!dq.empty()) {
    34. int t = dq.front();
    35. dq.pop_front();
    36. if (t == n)break;
    37. if (vis[t])continue;
    38. vis[t] = 1;
    39. for (int i = h[t]; i != -1; i = ne[i]) {
    40. int j = e[i];
    41. int v = w[i] >= mid;
    42. if (d[j] > d[t] + v) {
    43. d[j] = d[t] + v;
    44. if (v) {
    45. dq.push_back(j);
    46. }
    47. else {
    48. dq.push_front(j);
    49. }
    50. }
    51. }
    52. }
    53. return d[n] <= k;
    54. }
    55. int main() {
    56. cin >> n >> p >> k;
    57. memset(h, -1, sizeof h);
    58. for (int i = 1,a,b,c; i <= p; i++) {
    59. scanf("%d%d%d", &a, &b, &c);
    60. add(a, b, c);
    61. add(b, a, c);
    62. }
    63. int l = 0, r = 1e6 + 5, mid, ret = 0;
    64. while (l <= r) {
    65. mid = l + (r - l) / 2;
    66. if (check(mid)) {
    67. r = mid - 1;
    68. }
    69. else {
    70. ret = mid;
    71. l = mid + 1;
    72. }
    73. }
    74. if (ret > 1e6) {
    75. cout << -1 << endl;
    76. }
    77. else {
    78. cout << ret << endl;
    79. }
    80. return 0;
    81. }

     

    (此题还可用最短路中的分层图解,详情请看最短路分栏spfa,分层图,340. 通信线路,《算法竞赛进阶指南》_Landing_on_Mars的博客-CSDN博客

  • 相关阅读:
    自增还是UUID,数据库主键的类型该如何选择?
    每日一题(day10)
    数据结构高阶--AVL(平衡二叉树)(图解+实现)
    利用gpu加速神经网络算法,为什么用gpu 模型训练
    GMSL自学笔记
    MFC 窗体插入图片
    pandas 读取三种常见格式(txt、excel、csv)
    深入理解CyclicBarrie
    java继承简介说明
    Python中基于Socket实现服务器端和客户端之间的通信
  • 原文地址:https://blog.csdn.net/Landing_on_Mars/article/details/132651357