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,那就再随便选几个啦,然后再用非子集填补空缺。

 #include <cstdio>

 const int mxn = ;
const int mxm = ; int n, m, k; struct edge
{
int x, y, c;
}e[mxm]; int fa[mxn]; int find(int u)
{
return u == fa[u] ? u : fa[u] = find(fa[u]);
} bool vis[mxm]; signed main(void)
{
scanf("%d%d%d", &n, &m, &k); for (int i = ; i <= m; ++i)
scanf("%d%d%d",
&e[i].x,
&e[i].y,
&e[i].c); bool possible = true; {
int cnt = , root; for (int i = ; i <= n; ++i)fa[i] = i; for (int i = ; i <= m; ++i)
if (e[i].c)
{
int fx = find(e[i].x);
int fy = find(e[i].y); if (fx != fy)
fa[fx] = fy;
} for (int i = ; i <= m; ++i)
if (!e[i].c)
{
int fx = find(e[i].x);
int fy = find(e[i].y); if (fx != fy)
fa[fx] = fy, ++cnt, vis[i] = true;
} if (cnt > k)
possible = false; root = find(); for (int i = ; i <= n; ++i)
if (find(i) != root)
possible = false; k -= cnt;
} if (!possible)
return puts("no solution"), ; {
for (int i = ; i <= n; ++i)fa[i] = i; for (int i = ; i <= m; ++i)
if (vis[i])
{
int fx = find(e[i].x);
int fy = find(e[i].y); fa[fx] = fy;
} for (int i = ; i <= m; ++i)
if (!e[i].c && !vis[i] && k)
{
int fx = find(e[i].x);
int fy = find(e[i].y); if (fx != fy)
fa[fx] = fy, vis[i] = true, --k;
} for (int i = ; i <= m; ++i)
if (e[i].c)
{
int fx = find(e[i].x);
int fy = find(e[i].y); if (fx != fy)
fa[fx] = fy, vis[i] = true;
}
} for (int i = ; i <= m; ++i)
if (vis[i])printf("%d %d %d\n", e[i].x, e[i].y, e[i].c);
}

@Author: YouSiki

BZOJ 3624: [Apio2008]免费道路的更多相关文章

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

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

  2. BZOJ 3624 [Apio2008]免费道路:并查集 + 生成树 + 贪心【恰有k条特殊路径】

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3624 题意: 给你一个无向图,n个点,m条边. 有两种边,种类分别用0和1表示. 让你求一 ...

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

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

  4. BZOJ.3624.[APIO2008]免费道路(Kruskal)

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

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

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

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

  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. MapReduce -- 最短路径

    示例: 给出各个节点到相邻节点的距离,要求算出初始节点到各个节点的最短路径. 数据: A (B,) (D,) B (C,) (D,) C (E,) D (B,) (C,) (E,) E (A,) (C ...

  2. mfc CIPAddressCtrl控件

    知识点: CIPAddressCtrl 属性 CIPAddressCtrl 成员函数 成员函数代码测试 一.CIPAddressCtrl Class Members IsBlank Determine ...

  3. SPA程序加载首界面eclipse卡顿解决笔记

    最近在开发SPA程序项目时遇到一个问题,因为是在开发阶段,所以直接就在eclipse中启动项目. 每次进入首界面时,eclipse就会长时间卡顿,前端界面也加载不出来,很影响开发效率. 在查找问题的时 ...

  4. spring boot 实现文件下载

    html 代码 js部分 window.location.href= this.Baseurl+'/plan/down?file='+filename; spring boot 后台代码@GetMap ...

  5. C#_委托

    委托属于C#中的新名词,它的应用也非常广泛,例如事件就是委托最简单而又直接的例子. 那么首先说说什么是委托,其实委托在用过C或者C++的人看来就是函数指针,不过使用C#的大多数人都没有用过这两门语言, ...

  6. 博客配置Racket代码字体

    我想在博客园的文章中插入Racket代码,但是博客园的代码块和高亮都太难看了,如果能把scribble/manual的CSS文件中的Racket代码块的配置拿出来就可以有漂亮的Racket代码高亮了, ...

  7. WebGL模型拾取——射线法二

    这篇文章是对射线法raycaster的补充,上一篇文章主要讲的是raycaster射线法拾取模型的原理,而这篇文章着重讲使用射线法要注意的地方.首先我们来看下图. 我来解释一下上图中的originTr ...

  8. 用Unity简单实现第三人称人物的移动和转向

    上图不重要,因为实现人物的移动用的是动画,没有什么可说的,主要是下面实现人物的转向. 比如在一个平面中,玩家按了w和d键则人物会面向右前方向前进,如果此时玩家按了a和s键则人物会面向左后方向前进,那么 ...

  9. linux读书笔记(5章)

    linux读书笔记(5章) 标签(空格分隔): 20135328陈都 第五章 系统调用 5.1 与内核通信 系统调用 让应用程序受限的访问硬件设备 提供创建新进程并与已有进程通信的机制 提供申请操作系 ...

  10. 软件工程实践-git的使用

    ² Github使用心得 其实以前就注册过一个github账号,不过那时只不过是因为在网上看到这个挺对于程序员有着重大作用就顺手去弄了,从未使用过,直到这次软工实践需要我才从新回想起来. 之前的几篇随 ...