【luogu P3623 [APIO2008]免费道路】 题解
题目链接:https://www.luogu.org/problemnew/show/P3623
说是对克鲁斯卡尔的透彻性理解
正解:
先考虑加入水泥路,然后再考虑加入剩下必须要加入的最少鹅卵石路。
之后对原图再跑最小生成树
先跑鹅卵石路到k条。
再从所有水泥路中直到成为最小生成树。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100000 + 10;
int n, m, k, fa[maxn], cnt, shuini, eluan, tot;
bool f[maxn];
struct edge{
int u, v, w;
}e[maxn<<2], ans[maxn<<2];
bool cmp(edge a, edge b)
{
return a.w < b.w;
}
int find(int x)
{
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 1; i <= m; i++)
{
int opt;
scanf("%d%d%d",&e[i].u, &e[i].v, &opt);
if(opt == 0) e[i].w = 1, eluan++;
else e[i].w = 0, shuini++;
}
if(eluan < k)
{
cout<<"no solution\n";
return 0;
}
sort(e+1, e+1+m, cmp);
for(int i = 1; i <= shuini; i++)
{
if(cnt == n-1) break;
int rx, ry;
rx = find(e[i].u), ry = find(e[i].v);
if(rx != ry)
{
fa[ry] = rx;
cnt++;
}
}
int eluanmust = 0;
for(int i = shuini+1; i <= m; i++)
{
if(cnt == n-1) break;
int rx, ry;
rx = find(e[i].u), ry = find(e[i].v);
if(rx != ry)
{
fa[ry] = rx;
f[i] = 1, eluanmust++;
cnt++;
}
}
if(cnt != n-1 || eluanmust > k)
{
cout<<"no solution\n";
return 0;
}
for(int i = 1; i <= n; i++) fa[i] = i;
cnt = 0;
for(int i = shuini+1; i <= m; i++)
{
if(cnt == n-1) break;
if(f[i] == 1)
{
int rx, ry;
rx = find(e[i].u), ry = find(e[i].v);
fa[ry] = rx;
cnt++;
ans[++tot].u = e[i].u;
ans[tot].v = e[i].v;
ans[tot].w = e[i].w^1;
//printf("%d %d %d\n",e[i].u, e[i].v, e[i].w^1);
}
}
for(int i = shuini+1; i <= m; i++)
{
if(cnt == k) break;
int rx, ry;
rx = find(e[i].u), ry = find(e[i].v);
if(rx != ry)
{
fa[ry] = rx;
cnt++;
ans[++tot].u = e[i].u;
ans[tot].v = e[i].v;
ans[tot].w = e[i].w^1;
//printf("%d %d %d\n",e[i].u, e[i].v, e[i].w^1);
}
}
if(cnt < k)
{
cout<<"no solution\n";
return 0;
}
for(int i = 1; i <= shuini; i++)
{
if(cnt == n-1) break;
int rx, ry;
rx = find(e[i].u), ry = find(e[i].v);
if(rx != ry)
{
fa[ry] = rx;
cnt++;
ans[++tot].u = e[i].u;
ans[tot].v = e[i].v;
ans[tot].w = e[i].w^1;
//printf("%d %d %d\n",e[i].u, e[i].v, e[i].w^1);
}
}
if(cnt != n-1)
{
cout<<"no solution\n";
return 0;
}
for(int i = 1; i <= tot; i++)
printf("%d %d %d\n",ans[i].u, ans[i].v, ans[i].w);
return 0;
}
【luogu P3623 [APIO2008]免费道路】 题解的更多相关文章
- [火星补锅] 水题大战Vol.2 T2 && luogu P3623 [APIO2008]免费道路 题解
前言: 如果我自己写的话,或许能想出来正解,但是多半会因为整不出正确性而弃掉. 解析: 这题算是对Kruskal的熟练运用吧. 要求一颗生成树.也就是说,最后的边数是确定的. 首先我们容易想到一个策略 ...
- 题解 Luogu P3623 [APIO2008]免费道路
[APIO2008]免费道路 题目描述 新亚(New Asia)王国有 N 个村庄,由 M 条道路连接.其中一些道路是鹅卵石路,而其它道路是水泥路.保持道路免费运行需要一大笔费用,并且看上去 王国不可 ...
- P3623 [APIO2008]免费道路
3624: [Apio2008]免费道路 Time Limit: 2 Sec Memory Limit: 128 MBSec Special Judge Submit: 2143 Solved: 88 ...
- [BZOJ3624][Apio2008]免费道路
[BZOJ3624][Apio2008]免费道路 试题描述 输入 输出 输入示例 输出示例 数据规模及约定 见“输入”. 题解 第一步,先尽量加入 c = 1 的边,若未形成一个连通块,则得到必须加入 ...
- [APIO2008]免费道路
[APIO2008]免费道路 BZOJ luogu 先把必须连的鹅卵石路连上,大于k条no solution 什么样的鹅卵石路(u,v)必须连?所有水泥路都连上仍然不能使u,v连通的必须连 补全到k条 ...
- bzoj 3624: [Apio2008]免费道路 生成树的构造
3624: [Apio2008]免费道路 Time Limit: 2 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 111 Solved: 4 ...
- BZOJ 3624: [Apio2008]免费道路
3624: [Apio2008]免费道路 Time Limit: 2 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 1201 Solved: ...
- [Apio2008]免费道路[Kruscal]
3624: [Apio2008]免费道路 Time Limit: 2 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 1292 Solved: ...
- Kruskal算法及其类似原理的应用——【BZOJ 3654】tree&&【BZOJ 3624】[Apio2008]免费道路
首先让我们来介绍Krukal算法,他是一种用来求解最小生成树问题的算法,首先把边按边权排序,然后贪心得从最小开始往大里取,只要那个边的两端点暂时还没有在一个联通块里,我们就把他相连,只要这个图里存在最 ...
随机推荐
- mysql-profiling详解
要想优化一条 Query,我们就需要清楚的知道这条 Query 的性能瓶颈到底在哪里,是消耗的 CPU计算太多,还是需要的的 IO 操作太多?要想能够清楚的了解这些信息,在 MySQL 5.0 和 M ...
- 互联网轻量级框架SSM-查缺补漏第九天
简言: 第九章 Spring Ioc的概念 IoC(Inversion of Control)控制反转:比如想喝橙汁,在没有饮品店的日子,最直观的做法是买果汁机.橙汁.这是你自己“主动”创造的过程,也 ...
- hdu 1011 Starship Troopers 经典的树形DP ****
Starship Troopers Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- Selector#wakeup()
看thrift源码发现selector.wakeup()方法,通常在selector.select()后线程会阻塞.使用wakeup()方法,线程会立即返回.源码分析应该是用的线程中断实现的.下面是个 ...
- 纯CSS实现立方体旋转
下面为通过CSS动画实现的立方体旋转,可以改变CSS代码中关键帧定义(@keyframes)来改变立方体的旋转方式 HTML部分: <body class="body"> ...
- vue-cli脚手架之其他文件解释
好了,脚手架目录中重要的文件基本都介绍了,但还有一个不太注意到的文件没有解释,这里也说明一下. config文件夹下的index.js,作用是不同开发环境下的参数配置(可选项很多,生产环境.开发环境. ...
- canvas的Chart图表插件
今天写页面页面需求到柱状图标,今天介绍一下我所用的Chart.js图表插件 官网:http://www.bootcss.com/p/chart.js/ 里面会有下载js文件和中文文档 ...
- Java中生成帮助文档
如何在Java中使用注释 在编写程序时,经常需要添加一些注释,用以描述某段代码的作用. 一般来说,对于一份规范的程序源代码而言,注释应该占到源代码的 1/3 以上.因此,注释是程序源代码的重要组成部分 ...
- 任务十四:零基础JavaScript编码(二)
任务目的 在上一任务基础上继续JavaScript的体验 学习JavaScript中的if判断语法,for循环语法 学习JavaScript中的数组对象 学习如何读取.处理数据,并动态创建.修改DOM ...
- 关于cn.jedisoft.framework.annotations 的增删改查
今天在做一个crud的功能的时候,调用api老是调用不同.奇怪的是 在add的时候能添加进去,而删除和修改的时候不能成功. 最后反应过来,我在修改和删除的时候用的主键id是int类型的,接口类型是不能 ...