题目链接

我们发现有些白边是必须加的,有些是多余的。

那么我们先把所有黑边加进去,然后把必须要加的白边找出来。

然后Kruskal,把必须要加的白边先加进去,小于K的话再加能加的白边。然后加黑边。

要求最后是一棵树,没注意,刚开始以为白边还要多判次。

简便的写法:

//2464kb	96ms
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=2e4+5,M=1e5+5; int fa[N];
bool chose[M];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Edge
{
int fr,to,val;
inline void Print(){
printf("%d %d %d\n",fr,to,val);
}
bool operator <(const Edge &x)const{
return val<x.val;
}
}e[M]; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
#define Init() for(int i=1; i<=n; ++i) fa[i]=i
int Find(int x)
{
return x==fa[x]?x:fa[x]=Find(fa[x]);
}
bool Solve(int n,int m,int K)
{
Init();
std::sort(e+1,e+1+m);
int k=1;
for(int i=m,r1,r2; i; --i)
{
if((r1=Find(e[i].fr))==(r2=Find(e[i].to))) continue;
fa[r1]=r2;
if(!e[i].val) e[i].val=-1;//mark the white edge
if(++k==n) break;
}
if(k<n) return 0; Init();
std::sort(e+1,e+1+m);
int used=0; k=1;
for(int i=1,r1,r2; i<=m; ++i)
{
if((r1=Find(e[i].fr))==(r2=Find(e[i].to))) continue;
if(used<K || e[i].val==1)
{
fa[r1]=r2, chose[i]=1;
if(e[i].val<=0) e[i].val=0, ++used;
if(++k==n) break;
}
}
return used==K&&k==n;
} int main()
{
int n=read(),m=read(),K=read();
for(int i=1; i<=m; ++i) e[i]=(Edge){read(),read(),read()};
if(!Solve(n,m,K)) puts("no solution");
else for(int i=1; i<=m; ++i) if(chose[i]) e[i].Print(); return 0;
}

为了省掉sort闲的没事的写法:

//2904kb	76ms
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 250000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=2e4+5,M=1e5+5; int fa[N];
bool choseb[M],chosew[M];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Edge
{
int fr,to;
}b[M],w[M]; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
#define Init() for(int i=1; i<=n; ++i) fa[i]=i
int Find(int x)
{
return x==fa[x]?x:fa[x]=Find(fa[x]);
}
inline bool Union(int u,int v)
{
if(Find(u)!=Find(v)) {fa[fa[u]]=fa[v]; return 1;}
return 0;
}
bool Solve(int n,int m,int K,int bt,int wt)
{
if(wt<K) return 0;
Init();
int k=1;
for(int i=1; i<=bt; ++i) if(Union(b[i].fr,b[i].to)&&++k==n) break;
if(k<n)
for(int i=1; i<=wt; ++i)
{
if(!Union(w[i].fr,w[i].to)) continue;
chosew[i]=1;//mark the white edge
if(++k==n) break;
}
if(k<n) return 0; Init();
int used=0; k=1;
for(int i=1; i<=wt; ++i)
if(chosew[i]&&Union(w[i].fr,w[i].to))
if(++used, ++k==n) break;
if(used>K) return 0;
if(k<n&&used<K)
for(int i=1; i<=wt; ++i)
if(!chosew[i]&&Union(w[i].fr,w[i].to))
{
chosew[i]=1, ++used, ++k;
if(k==n||used==K) break;
}
if(used<K) return 0;
if(k<n)
for(int i=1; i<=bt; ++i)
{
if(!Union(b[i].fr,b[i].to)) continue;
choseb[i]=1;
if(++k==n) break;
}
return k==n;
} int main()
{
int n=read(),m=read(),K=read(),bt=0,wt=0;
for(int i=1,u,v; i<=m; ++i)
if(u=read(),v=read(),read()) b[++bt]=(Edge){u,v};
else w[++wt]=(Edge){u,v};
if(!Solve(n,m,K,bt,wt)) puts("no solution");
else
{
for(int i=1; i<=wt; ++i) if(chosew[i]) printf("%d %d 0\n",w[i].fr,w[i].to);
for(int i=1; i<=bt; ++i) if(choseb[i]) printf("%d %d 1\n",b[i].fr,b[i].to);
} return 0;
}

BZOJ.3624.[APIO2008]免费道路(Kruskal)的更多相关文章

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

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

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

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

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

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

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

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

  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. Python内置函数之匿名(lambda)函数

    Python内置函数之匿名(lambda)函数 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.匿名函数 #!/usr/bin/env python #_*_coding:utf ...

  2. spring boot 分布式事务实现(XA方式)

    关于spring boot 支持分布式事务,XA是常用的一种方式. 这里把相关的配置记下,方便以后使用. 首先配置两个不同的数据源 : 订单库.持仓库. /** * Created by zhangj ...

  3. bzoj千题计划270:bzoj4559: [JLoi2016]成绩比较(拉格朗日插值)

    http://www.lydsy.com/JudgeOnline/problem.php?id=4559 f[i][j] 表示前i门课,有j个人没有被碾压的方案数 g[i] 表示第i门课,满足B神排名 ...

  4. Docker 入门 第一部分: 定位和设置

    目录 Docker 入门 第一部分: 定位和设置 Docker概念 镜像和容器 容器和虚拟机 准备你的Docker环境 测试 Docker 的版本 测试 Docker 安装 回顾 总结 Docker ...

  5. js 语法高亮插件之 Prism.js

    之前也介绍过几款语法高亮插件<为博客园选择一个小巧霸气的语法高亮插件>以及关于他们的综合性能<再议 语法高亮插件的选择>.今天在小影志博客看到<使用 Prism.js 实 ...

  6. 工欲善其事必先利其器,用Emmet提高HTML编写速度

    HTML代码写起来很费事,因为它的标签多. 一种解决方法是采用模板,在别人写好的骨架内,填入自己的内容.还有一种很炫的方法----简写法. 常用的简写法,目前主要是Emmet和Haml两种.这两种简写 ...

  7. 【配置】Spring Struts配置信息

  8. C - 青蛙的约会 POJ - 1061 (扩展欧几里得)

    题目链接:https://cn.vjudge.net/contest/276376#problem/C 题目大意:中文题目. 具体思路:扩展gcd,具体证明过程看图片(就这麽个题我搞了一天,,,). ...

  9. D. Dasha and Chess(交互题)

    题目链接:http://codeforces.com/contest/1100/problem/D 题目大意:给你一个999*999的图,然后有666个黑色旗子,一个白色棋子,每一次白色棋子只能在它附 ...

  10. 什么是BS,BS和CS的区别有哪些

    BS和CS的区别以及优缺点 C/S又称Client/Server或客户/服务器模式.服务器通常采用高性能的PC.工作站或小型机,并采用大型数据库系统,如Oracle.Sybase.Informix或 ...