题目链接

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

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

然后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. DNA序列编码中Hairpin的定义和计算

    DNA序列编码中Hairpin的定义和计算 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文献 [1] 张凯. DNA计算核酸编码优化及算法设计[D]. 2008. [2] Shin, ...

  2. CentOS6.8下安装Nginx-1.9.15

    1. 简介 Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP代理服务器. Nginx是一款轻量级的Web服务器/反向代理服务器以及电子邮件代理服务器,并在一个BS ...

  3. Firefox滚动残影(转)

    Firefox滚动残影   Firefox滚动残影这文章放在草稿箱有一阵子了,之前的3系列都有这BUG,当正想发表这文章的时候,和我沟通刚刚升级的FF4已修复此BUG,所以搁置一阵在考虑到这文章还有没 ...

  4. BZOJ4103 异或运算

    4103: [Thu Summer Camp 2015]异或运算 Time Limit: 20 Sec  Memory Limit: 512 MB Description 给定长度为n的数列X={x1 ...

  5. 20155203 2016-2017-2 《Java程序设计》第7周学习总结

    20155203 2016-2017-2 <Java程序设计>第6周学习总结 教材学习内容总结 1.Lambda表达式.(使用interface函数接口) 2.Lambda的方法参考Met ...

  6. MySQL忘记密码了怎么办?

    接手一个项目时,如果上一位负责人没有把项目文档.账号密码整理好是一件很头疼的事情.. 例如,当你想打开MySQL数据库的时候 输入: mysql -u root -p 一回车想输入密码,发现密码错误! ...

  7. 用U盘安装 win7 ”找不到任何设备驱动程序“ 和 系统出现 windows boot manager 解决方案

    用U盘安装win7系统时,系统交替的出现了如下的2个错误,捣鼓了半天,记录下来: 问题1描述: 安装win7时  ”找不到任何设备驱动程序“  问题2描述: 安装win7时,用U盘启动后, 系统出现 ...

  8. 【源码阅读】Mimikatz相关资料

    Mimikatz GitHub (源码) https://github.com/gentilkiwi/mimikatz Mimikatz GitHub Wiki (包含了一些说明文档) https:/ ...

  9. pop3设置

  10. Visual Studio 2012“完美的拥抱”Visual Studio Online

    看了Visual Studio 2012完美的拥抱GitHub 写的不错,不过,配置起来太麻烦.既然是使用VS编码,微软的东西嘛,当然还有更简单的,那就是Visual Studio Online.不用 ...