• BZOJ 3624: [Apio2008]免费道路


    3624: [Apio2008]免费道路

    Time Limit: 2 Sec  Memory Limit: 128 MBSec  Special Judge
    Submit: 1201  Solved: 469
    [Submit][Status][Discuss]

    Description

    Input

    Output

    Sample Input

    5 7 2
    1 3 0
    4 5 1
    3 2 0
    5 3 1
    4 3 0
    1 2 1
    4 2 1

    Sample Output

    3 2 0
    4 3 0
    5 3 1
    1 2 1

    HINT

     

    Source

     
    [Submit][Status][Discuss]

    哎呀,这题好气啊,明明不难的,就是想不到啊,还是我太蒟蒻了啊。

    题意要求我们求出一棵生成树,但是这次限制的不是权值大小,而是在一个给定的边集的子集中选出恰好K条边加入生成树,输出任意一种方案即可,SPJ。

    这个其实很简单,你就先紧着子集里的边加,做Kruskal,求出一棵生成树(也许只能做出一棵生成森林),这是你保证了子集中选出的边>=K(如果小于K那就是无解啦),这时先用子集外的边填补漏洞,把森林补成树(补不成就是无解啦),然后再不断尝试加入子集外的边,显然加入之后会有环,那么替换掉环上的一条子集边即可(如果环上有的话),这个用LCT维护就好了,反正N<=20000是吧。

    其实上面只是开玩笑的,如果你真的像我一开始这么想,看到Time Limit你就绝望了,23333——手动滑稽

    正解是先紧着子集外的边加,造一个森林(能是树最好啦),然后用子集内的边补上不连通的位置。如果不能补成树或使用的子集边>K,那么就是无解。那么此时用来填补非子集边无法做到的联通性的边(就是刚才选出来的子集边)是一定要选的(并非必须边,但是一定存在一组可行解包含它们)。那么先选上这些,下面我们一定可以用非子集边把图连成生成树了,但是可能子集边还不到K,那就再随便选几个啦,然后再用非子集填补空缺。

      1 #include <cstdio>
      2 
      3 const int mxn = 20005;
      4 const int mxm = 100005;
      5 
      6 int n, m, k;
      7 
      8 struct edge
      9 {
     10     int x, y, c;
     11 }e[mxm];
     12 
     13 int fa[mxn];
     14 
     15 int find(int u)
     16 {
     17     return u == fa[u] ? u : fa[u] = find(fa[u]);
     18 }
     19 
     20 bool vis[mxm];
     21 
     22 signed main(void)
     23 {
     24     scanf("%d%d%d", &n, &m, &k);
     25     
     26     for (int i = 1; i <= m; ++i)
     27         scanf("%d%d%d",
     28             &e[i].x,
     29             &e[i].y,
     30             &e[i].c);
     31     
     32     bool possible = true;
     33     
     34     {
     35         int cnt = 0, root;
     36         
     37         for (int i = 1; i <= n; ++i)fa[i] = i;
     38         
     39         for (int i = 1; i <= m; ++i)
     40             if (e[i].c)
     41             {
     42                 int fx = find(e[i].x);
     43                 int fy = find(e[i].y);
     44                 
     45                 if (fx != fy)
     46                     fa[fx] = fy;
     47             }
     48         
     49         for (int i = 1; i <= m; ++i)
     50             if (!e[i].c)
     51             {
     52                 int fx = find(e[i].x);
     53                 int fy = find(e[i].y);
     54                 
     55                 if (fx != fy)
     56                     fa[fx] = fy, ++cnt, vis[i] = true;
     57             }
     58         
     59         if (cnt > k)
     60             possible = false;
     61             
     62         root = find(1);
     63         
     64         for (int i = 2; i <= n; ++i)
     65             if (find(i) != root)
     66                 possible = false;
     67         
     68         k -= cnt;
     69     }
     70     
     71     if (!possible)
     72         return puts("no solution"), 0;
     73     
     74     {
     75         for (int i = 1; i <= n; ++i)fa[i] = i;
     76         
     77         for (int i = 1; i <= m; ++i)
     78             if (vis[i])
     79             {
     80                 int fx = find(e[i].x);
     81                 int fy = find(e[i].y);
     82                 
     83                 fa[fx] = fy;
     84             }
     85         
     86         for (int i = 1; i <= m; ++i)
     87             if (!e[i].c && !vis[i] && k)
     88             {
     89                 int fx = find(e[i].x);
     90                 int fy = find(e[i].y);
     91                 
     92                 if (fx != fy)
     93                     fa[fx] = fy, vis[i] = true, --k;
     94             }
     95         
     96         for (int i = 1; i <= m; ++i)
     97             if (e[i].c)
     98             {
     99                 int fx = find(e[i].x);
    100                 int fy = find(e[i].y);
    101                 
    102                 if (fx != fy)
    103                     fa[fx] = fy, vis[i] = true;
    104             }
    105     }
    106     
    107     for (int i = 1; i <= m; ++i)
    108         if (vis[i])printf("%d %d %d
    ", e[i].x, e[i].y, e[i].c);
    109 }

    @Author: YouSiki

  • 相关阅读:
    [NOI2003][bzoj1507] 文本编辑器 editor [splay]
    GDKOI 游记
    [填坑完毕] 寒假作业计划
    省选算法学习-数据结构-splay
    NOIP2017游记
    真·总结
    赛前
    十一黄(xun)金(lian)周感想
    9.17 模拟赛
    9.14 模拟赛
  • 原文地址:https://www.cnblogs.com/yousiki/p/6430702.html
Copyright © 2020-2023  润新知