题目链接

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

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

然后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. ASP.NET MVC学习笔记-----Filter(2)

    接上篇ASP.NET MVC学习笔记-----Filter(1) Action Filter Action Filter可以基于任何目的使用,它需要实现IActionFilter接口: public ...

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

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

  3. html5 canvas 垂直渐变描边

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. 关于Spring mvc注解中的定时任务的配置

    关于spring mvc注解定时任务配置 简单的记载:避免自己忘记,不是很确定我理解的是否正确.有错误地方望请大家指出. 1,定时方法执行配置: (1)在applicationContext.xml中 ...

  5. 【转】教你何时开启水果机上的HDR拍照

    原址:http://news.mydrivers.com/1/175/175922.htm 苹果在iOS 4.1操作系统中为iPhone 4增加了一项有趣的新功能:HDR拍照.虽然目前市场上支持HDR ...

  6. Hibernate的实体规则、主键生成策略、对象状态

    一. hibernate的实体类有一定的规则,类似于mybatis的逆向工程导出的实体类.具体的规则以及原因如下: 1.持久化类需要提供无参的构造方法. 因为hibernate底层采用反射机制创建对象 ...

  7. TensorFlow 从零到helloWorld

    目录 1.git安装与使用 1.1 git安装 1.2 修改git bash默认路径 1.3 git常用操作 2.环境搭建   2.1 tensorflow安装   2.2 CUDA安装   2.3 ...

  8. 2010 NEERC Western subregional

    2010 NEERC Western subregional Problem A. Area and Circumference 题目描述:给定平面上的\(n\)个矩形,求出面积与周长比的最大值. s ...

  9. Entity Framework 6.1.0 Tools for Visual Studio 2012 & 2013

    http://www.microsoft.com/en-us/download/confirmation.aspx?id=40762

  10. python tqdm函数

    tqdm是个显示进度条的库.很是方便,还有个tqdm_gui貌似可以显示GUI图像.以后有空再研究. 贴张别人的图,看一下就清楚了.