免费道路

Time Limit: 2 Sec  Memory Limit: 128 MB
[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

  1<=n<=20000,1<=m<=100000,0<=k<=n-1

Main idea

  一种0边,一种1边,求一棵最小生成树并且正好有K条0边,输出其中一种方案。

Solution

  显然要搞一棵符合题目的生成树。

  每次要加入0边或者1边,直接做肯定不可行,考虑有什么0边是一定要加入的。

  只需要输出一种方案,所以我们先加入所有可加的1边,如果图不联通则加入可加入的0边,那么这几条0边在我们所求的方案中是一定需要加入的。

  这时候判断一下,如果此时加入的0边数量>K,或者图还是无法联通的话则无解。然后处理完毕前半部分,考虑接下来如何实现。

  因为我们要使得图为树并且正好有K条0边,运用贪心,想到了加入0边到K条位置(如果到不了K条则也无解),然后剩下的用1边来填。

  验证一下这样做的可行性:由于我们在前半部分使得了可以成为一棵树,那么显然我们在后半部分中每加入一条0边,则在前半部分中一定有一条1边可以替换使得可行(因为前半部分是尽量加入1边)。每次连边判环运用Krusal即可。

Code

 #include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std; const int ONE=;
const int INF=; int n,m,k;
int Edge_k;
int fa[ONE];
int num;
int Choose[ONE];
int ans_num;
int the0; struct power
{
int x,y,v;
}a[ONE],Ans_edg[ONE]; int get()
{
int res,Q=; char c;
while( (c=getchar())< || c>)
if(c=='-')Q=-;
if(Q) res=c-;
while((c=getchar())>= && c<=)
res=res*+c-;
return res*Q;
} int find(int x)
{
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
} void Un(int a,int b)
{
int a1=find(a);
int b1=find(b);
if(a1!=b1) fa[a1]=b1;
} int Add_set(int N,int v,int ci)
{
int kd=;
for(int i=;i<=m;i++)
{
if(kd>=N) break; if(a[i].v!=v) continue; int x=a[i].x,y=a[i].y;
if(find(x)!=find(y))
{
Un(x,y);
if(ci>=) Ans_edg[++ans_num]=a[i];
if(ci==)
{
Choose[++num]=i;
}
Edge_k++;
kd++;
if(ci==) the0++;
}
if(Edge_k==n-) break;
}
} int main()
{
n=get(); m=get(); k=get();
for(int i=;i<=n;i++) fa[i]=i;
for(int i=;i<=m;i++)
{
a[i].x=get(); a[i].y=get(); a[i].v=get();
}
Edge_k=; Add_set(INF,,);
Add_set(INF,,); if(Edge_k<n- || num>k)
{
printf("no solution\n");
return ;
} Edge_k=;
for(int i=;i<=n;i++) fa[i]=i;
for(int i=;i<=num;i++)
{
int x=Choose[i];
Un(a[x].x,a[x].y);
Edge_k++;
if(Edge_k==n-) break;
} Add_set(k-num,,);
if(the0!=k-num)
{
printf("no solution\n");
return ;
} Add_set(INF,,);
for(int i=;i<=ans_num;i++)
{
printf("%d %d %d\n",Ans_edg[i].x,Ans_edg[i].y,Ans_edg[i].v);
} }

【BZOJ3624】【APIO2008】免费道路 [生成树][贪心]的更多相关文章

  1. [BZOJ3624][Apio2008]免费道路

    [BZOJ3624][Apio2008]免费道路 试题描述 输入 输出 输入示例 输出示例 数据规模及约定 见“输入”. 题解 第一步,先尽量加入 c = 1 的边,若未形成一个连通块,则得到必须加入 ...

  2. bzoj 3624: [Apio2008]免费道路 生成树的构造

    3624: [Apio2008]免费道路 Time Limit: 2 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 111  Solved: 4 ...

  3. [APIO2008]免费道路(生成树)

    新亚(New Asia)王国有 N 个村庄,由 M 条道路连接.其中一些道路是鹅卵石路,而其它道路是水泥路.保持道路免费运行需要一大笔费用,并且看上去 王国不可能保持所有道路免费.为此亟待制定一个新的 ...

  4. Bzoj 3624: [Apio2008]免费道路 (贪心+生成树)

    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 这 ...

  5. BZOJ 3624: [Apio2008]免费道路 [生成树 并查集]

    题意: 一张图0,1两种边,构造一个恰有k条0边的生成树 优先选择1边构造生成树,看看0边是否小于k 然后保留这些0边,补齐k条,再加1边一定能构成生成树 类似kruskal的证明 #include ...

  6. BZOJ3624: [Apio2008]免费道路(最小生成树)

    题意 题目链接 Sol 首先答案一定是一棵树 这棵树上有一些0边是必须要选的,我们先把他们找出来,如果数量$\geqslant k$显然无解 再考虑继续往里面加0的边,判断能否加到k条即可 具体做法是 ...

  7. Kruskal算法及其类似原理的应用——【BZOJ 3654】tree&&【BZOJ 3624】[Apio2008]免费道路

    首先让我们来介绍Krukal算法,他是一种用来求解最小生成树问题的算法,首先把边按边权排序,然后贪心得从最小开始往大里取,只要那个边的两端点暂时还没有在一个联通块里,我们就把他相连,只要这个图里存在最 ...

  8. 题解 Luogu P3623 [APIO2008]免费道路

    [APIO2008]免费道路 题目描述 新亚(New Asia)王国有 N 个村庄,由 M 条道路连接.其中一些道路是鹅卵石路,而其它道路是水泥路.保持道路免费运行需要一大笔费用,并且看上去 王国不可 ...

  9. BZOJ 3624: [Apio2008]免费道路

    3624: [Apio2008]免费道路 Time Limit: 2 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 1201  Solved:  ...

随机推荐

  1. APIO2018 游记

    day \(-\infty\) \(\sim\) day0 5 月 5 号左右的时候去了趟中北大学,山西省大学生程序设计竞赛.不是太满意,现场 rk3.拿到了充电宝(冲着这个去的,虽然抵不过车费),抽 ...

  2. LeetCode高频题目(100)汇总-Java实现

    LeetCode高频题目(100)汇总-Java实现       LeetCode高频题目(100)汇总-Java实现 目录 第01-50题 [Leetcode-easy-1] Two Sum [Le ...

  3. c++ list_iterator demo

    #include <iostream> #include <list> using namespace std; typedef list<int> Integer ...

  4. Percona-Tookit工具包之pt-find

      Preface       We used to use "find" command in linux or AIX when we need to get a certai ...

  5. Selenium 启动无头浏览器,只有chrome 和 firefox的,没有IE

    使用无头浏览器,可以避免掉不确定的弹出框对脚本稳定性的影响,还能在脚本执行过程中省略掉了css 加载的时间. 以下是Selenium 启动无头浏览器的方法,只有chrome 和 firefox的. p ...

  6. 【java并发编程实战】第八章:线程池的使用

    1.线程饥饿锁 定义:在线程池中,如果任务的执行依赖其他任务,那么可能会产生线程饥饿锁.尤其是单线程线程池. 示例: public class ThreadDeadStarveTest { publi ...

  7. CSP201604-1:折点计数

    引言:CSP(http://www.cspro.org/lead/application/ccf/login.jsp)是由中国计算机学会(CCF)发起的"计算机职业资格认证"考试, ...

  8. AM5728通过GPMC接口与FPGA高速数据通信实现

    硬件:AM5728开发板:Artix-7开发板软件:Linux am57xx-evm 4.4.19:Vivado 2015.2作者:杭州矢志信息科技有限公司邮箱:admin@sysjoint.com ...

  9. Python 并发编程:PoolExecutor 篇

    个人笔记,如有疏漏,还请指正. 使用多线程(threading)和多进程(multiprocessing)完成常规的并发需求,在启动的时候 start.join 等步骤不能省,复杂的需要还要用 1-2 ...

  10. RMQ问题+ST算法

    一.相关定义 RMQ问题 求给定区间的最值: 一般题目给定许多询问区间. 常见问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j之间的最小/大 ...