• [BZOJ2654] tree (kruskal & 二分答案)


    Description

      给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
      题目保证有解。 

    Input

      第一行V,E,need分别表示点数,边数和需要的白色边数。
      接下来E行
      每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。 

    Output

      一行表示所求生成树的边权和。 

    Sample Input

    2 2 1
    0 1 1 1
    0 1 2 0

    Sample Output

    2

    HINT

      数据规模和约定
      0:V<=10
      1,2,3:V<=15
      0,..,19:V<=50000,E<=100000
      所有数据边权为[1,100]中的正整数。

    Source

    Solution

      如果给所有白色边加上一个权值,所形成的最小生成树的白边数会随该权值的增大而减小,满足单调性,可以二分权值。

      排序有一个技巧:我们每次考虑最多可以使用多少条白边,所以排序时若权值相同,白边排前黑边排后。如果排序不管黑边白边,那么所求的白边数会小于期望的答案,可能会导致WA。

      当然黑边在前白边在后也行,题是死的人是活的。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 struct edge
     4 {
     5     int u, v, w, col;
     6     bool operator < (const edge &rhs) const
     7     {
     8         return w == rhs.w ? col < rhs.col : w < rhs.w;
     9     }
    10 }e[100005];
    11 int n, m, fa[50005], ans;
    12  
    13 int getfa(int x)
    14 {
    15     return fa[x] = x == fa[x] ? x : getfa(fa[x]);
    16 }
    17  
    18 int Kruskal(int x)
    19 {
    20     int ecnt = 0, wcnt = 0, u, v;
    21     ans = 0;
    22     for(int i = 1; i <= n; i++)
    23         fa[i] = i;
    24     for(int i = 1; i <= m; i++)
    25         if(!e[i].col) e[i].w += x;
    26     sort(e + 1, e + m + 1);
    27     for(int i = 1; i <= m; i++)
    28     {
    29         u = getfa(e[i].u), v = getfa(e[i].v);
    30         if(u != v)
    31         {
    32             fa[v] = u, ans += e[i].w;
    33             if(!e[i].col) wcnt++;
    34             if(++ecnt >= n) break;
    35         }
    36     }
    37     for(int i = 1; i <= m; i++)
    38         if(!e[i].col) e[i].w -= x;
    39     return wcnt;
    40 }
    41  
    42 int main()
    43 {
    44     int k, l = -105, r = 105, mid;
    45     cin >> n >> m >> k;
    46     for(int i = 1; i <= m; i++)
    47         cin >> e[i].u >> e[i].v >> e[i].w >> e[i].col;
    48     for(int i = 1; i <= m; i++)
    49         e[i].u++, e[i].v++;
    50     while(l < r - 1)
    51     {
    52         mid = (l + r) / 2;
    53         if(Kruskal(mid) < k) r = mid;
    54         else l = mid;
    55     }
    56     Kruskal(l);
    57     cout << ans - l * k << endl;
    58     return 0;
    59 }
    View Code
  • 相关阅读:
    在监控落地的路上,助你一臂之力
    一文讲透数据结构中的树,建议收藏!
    别人家的 InfluxDB 实战 + 源码剖析
    从 React 架构开始讲解 useState、useEffect 编程设计
    事件捕获、事件冒泡、事件委托
    JavaScript设计模式学习笔记
    复制到剪贴板,粘贴进微信,换行符失效
    curl: (7) Failed to connect to raw.githubusercontent.com port 443: Connection refused
    nodejs版本管理工具n教程
    手把手教你撸一套Redux(Redux源码解读)
  • 原文地址:https://www.cnblogs.com/CtrlCV/p/5417235.html
Copyright © 2020-2023  润新知