题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3624

题意:

  给你一个无向图,n个点,m条边。

  有两种边,种类分别用0和1表示。

  让你求一棵生成树,使得这棵树中恰好有k条0种类的边。输出每一条边的两端点和种类。

  若无解,则输出"no solution"。

题解:

  让0和1分别作两种边的边权。

  步骤:

    (1)先找出必须选的0边。(优先选1,最大生成树)

    (2)再将0边个数加至k。

    (3)补上1边。

AC Code:

 #include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define MAX_N 20005 using namespace std; struct Edge
{
int sour;
int dest;
int len;
Edge(int _sour,int _dest,int _len)
{
sour=_sour;
dest=_dest;
len=_len;
}
Edge(){}
friend bool operator < (const Edge &a,const Edge &b)
{
return a.len<b.len;
}
}; int n,m,k;
int par[MAX_N];
bool failed=false;
vector<Edge> edge;
vector<Edge> est;
vector<Edge> ans; void read()
{
cin>>n>>m>>k;
int a,b,c;
for(int i=;i<m;i++)
{
cin>>a>>b>>c;
edge.push_back(Edge(a,b,c));
}
} void init_union_find()
{
for(int i=;i<=n;i++)
{
par[i]=i;
}
} int find(int x)
{
return par[x]==x?x:par[x]=find(par[x]);
} void unite(int x,int y)
{
int px=find(x);
int py=find(y);
if(px==py) return;
par[px]=py;
} bool same(int x,int y)
{
return find(x)==find(y);
} void max_tree()
{
init_union_find();
sort(edge.begin(),edge.end());
int cnt=;
for(int i=edge.size()-;i>=;i--)
{
Edge temp=edge[i];
if(!same(temp.sour,temp.dest))
{
cnt++;
unite(temp.sour,temp.dest);
if(temp.len==) est.push_back(temp);
}
}
if(cnt!=n- || est.size()>k) failed=true;
} void min_tree()
{
init_union_find();
int cnt=;
int spe=;
for(int i=;i<est.size() && spe<k;i++)
{
Edge temp=est[i];
cnt++;
spe++;
ans.push_back(temp);
unite(temp.sour,temp.dest);
}
for(int i=;i<edge.size();i++)
{
Edge temp=edge[i];
if(!same(temp.sour,temp.dest))
{
if(temp.len==)
{
if(spe<k)
{
cnt++;
spe++;
ans.push_back(temp);
unite(temp.sour,temp.dest);
}
}
else
{
cnt++;
ans.push_back(temp);
unite(temp.sour,temp.dest);
}
}
}
if(cnt!=n- || spe!=k) failed=true;
} void solve()
{
max_tree();
min_tree();
} void print()
{
if(failed)
{
cout<<"no solution"<<endl;
return;
}
for(int i=;i<ans.size();i++)
{
Edge temp=ans[i];
cout<<temp.sour<<" "<<temp.dest<<" "<<temp.len<<endl;
}
} int main()
{
read();
solve();
print();
}

BZOJ 3624 [Apio2008]免费道路:并查集 + 生成树 + 贪心【恰有k条特殊路径】的更多相关文章

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

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

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

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

  3. bzoj 3624: [Apio2008]免费道路【生成树+贪心】

    先把水泥路建生成树,然后加鹅卵石路,这里加的鹅卵石路是一定要用的(连接各个联通块),然后初始化并查集,先把必需的鹅卵石路加进去,然后随便加鹅卵石路直到k条,然后加水泥路即可. 注意判断无解 #incl ...

  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. BZOJ.3624.[APIO2008]免费道路(Kruskal)

    题目链接 我们发现有些白边是必须加的,有些是多余的. 那么我们先把所有黑边加进去,然后把必须要加的白边找出来. 然后Kruskal,把必须要加的白边先加进去,小于K的话再加能加的白边.然后加黑边. 要 ...

  7. 3624: [Apio2008]免费道路

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

  8. [Apio2008]免费道路[Kruscal]

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

  9. P3623 [APIO2008]免费道路

    3624: [Apio2008]免费道路 Time Limit: 2 Sec Memory Limit: 128 MBSec Special Judge Submit: 2143 Solved: 88 ...

随机推荐

  1. "贪心法"

    有没有想过 “==” 和“= =” 的区别 , 万一编译器曲解了你的意思,那不是爽歪歪! C语言编译器会把前面的符号当做一个整体,后面的不再. 当我们遇到指针相除时: y=x/*p 编译器会怎样? 和 ...

  2. 代理server的概要知识

    技术支持请留言:http://www.lcpower.cn 一.什么是代理server? 代理server英文全称是Proxy Server.其功能就是代理网络用户去取得网络信息.形象的说:它是网络信 ...

  3. sql 时间相关

    1.常用日期方法(下面的GetDate() = '2006-11-08 13:37:56.233') (1)DATENAME ( datepart ,date ) 返回表示指定日期的指定日期部分的字符 ...

  4. winform 下载文件显示进度和百分比

    /// <summary> /// 下载完成 /// </summary> private void DownloadFileCompleted() { IsComlate = ...

  5. 转:RC复位电路的原理及其复位时间的计算

    RC复位电路的原理及其复位时间的计算   低电平有效复位电路如下 此复位电路是针对低电平有效复位而言的,其中二极管是起着在断电的情况下能够很快的将电容两端的电压释放掉,为下次上电复位准备. 假设电容两 ...

  6. 并发insert情况下数据重复插入问题的解决方案

    背景介绍 通常我们在接口里要保存一条数据时,会先判断该条记录在数据库里是否存在,如果不存在就插入,如果存在就返回已经存在. 就拿常见的工单来举例 Order order = orderService. ...

  7. Android 开源项目精选

    0x00  leakcanary [内存泄漏检测] Leakcanary : A memory leak detection library for Android and Java. 良心企业Squ ...

  8. 【Java】 Spring依赖注入小试牛刀:编写第一个Spring ApplicationContext Demo

    0  Spring的依赖注入大致是这样工作的: 将对象如何构造(ID是什么?是什么类型?给属性设置什么值?给构造函数传入什么值?)写入外部XML文件里.在调用者需要调用某个类时,不自行构造该类的对象, ...

  9. 理解cas

    前言 CAS(Compare and Swap),即比较并替换,实现并发算法时常用到的一种技术,Doug lea大神在java同步器中大量使用了CAS技术,鬼斧神工的实现了多线程执行的安全性. CAS ...

  10. Unity3D自定义编辑器简单实例

    MenuItem:在标题栏自定义菜单.需要在Editor文件夹内创建脚本,无需挂载.但是注意其下的函数必须为静态函数. using UnityEngine; using UnityEditor; pu ...