题目链接

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

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

然后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. Markdown 详细语法

    << 访问 Wow!Ubuntu NOTE: This is Simplelified Chinese Edition Document of Markdown Syntax. If yo ...

  2. jdk 动态代理实现对目标对象的增强

    因为学习 spring框架的 AOP 所以,这里复习下动态代理,但是 spring 的底层动态代理实现是 cglib,jdk 这种呢可以引导新手入门 spring AOP 横向抽取机制 最典型的应用当 ...

  3. jenkins设置CSRF 协议(CRUMB值设置)

    在关闭“”调用出现Error 403 No valid crumb was included in the request 第一种解决方式是 关闭 csrf,如上图,去掉勾就可以,但是并不推荐. 第二 ...

  4. springboot(五):springboot整合shiro-登录认证和权限管理

    http://z77z.oschina.io/ http://www.cnblogs.com/aqsunkai/category/982003.html https://www.cnblogs.com ...

  5. AngularJS -- 代码实例

    整理书籍内容(QQ:283125476 发布者:M [重在分享,有建议请联系->QQ号]) ng-change 当文本输入字段中内容发生了变化,就会改变equation.x的值: <bod ...

  6. tensorflow随机张量创建

    TensorFlow 有几个操作用来创建不同分布的随机张量.注意随机操作是有状态的,并在每次评估时创建新的随机值. 下面是一些相关的函数的介绍: tf.random_normal 从正态分布中输出随机 ...

  7. CTSC/APIO2018滚粗记

    CTSC/APIO2018滚粗记 前言 从\(5.5\)晚上的火车到\(5.14\)早上的高铁 \(10\)天的时间真的过去的很快. 眨眼间,就到了今天晚上的颁奖. 至于结果如何,反而并不是那么重要了 ...

  8. python3转变exe的方法

    python开发的代码可能在其他windows上并不能使用用,除非别人的环境中也有python. 下面是如何将python开发的东西转为exe格式 1.安装pyinstaller pip instal ...

  9. python基础--模块使用

      一:模块介绍 模块分为三种: 自定义模块 内置标准模块(又称标准库) 开源模块 自定义模块使用 # -*- coding:utf-8 -*- __author__ = 'shisanjun' &q ...

  10. webRTC视频通话,https协议,录制端和播放端

    最近做视频直播模块,在网上也看到很多大神写的代码,写的都不错,但不是我想要的,有的可能比较老,不支持https协议,有的又将直播端和显示端放在一个程序中,不利于我使用,则本篇着重添加了https协议( ...