3624: [Apio2008]免费道路

Time Limit: 2 Sec  Memory Limit: 128 MBSec  Special Judge
Submit: 1292  Solved: 518
[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

自己的第一次思路:
  小数据枚举k条鹅卵石路,大数据随机找k条鹅卵石路,跟剩下的水泥路构树,如果可以构成树,则此方案可行。
  随机化的阈值我设置的是20.

  然后就砍到72分。

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2e4+;
const int M=1e5+;
struct edge{int u,v,w,id;}e[M],z[M];
int n,m,num0,K,tot,cct,fa[N],ans[M];
int a[];bool vis[];
inline int read(){
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline bool cmp(const edge &a,const edge &b){
return a.id<b.id;
}
inline bool cmp2(const edge &a,const edge &b){
return a.w<b.w;
}
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void pre(){
tot=;ans[]=;
for(int i=;i<=n;i++) fa[i]=i;
random_shuffle(e+,e+num0+);
for(int i=,x,y;i<=num0;i++){
x=find(e[i].u);y=find(e[i].v);
if(x!=y){
fa[y]=x;ans[++ans[]]=i;
if(++tot==K) break;
}
}
}
inline void ord(){
tot=;ans[]=;
for(int i=;i<=n;i++) fa[i]=i;
for(int i=,x,y;i<=K;i++){
x=find(e[a[i]].u);y=find(e[a[i]].v);
if(x!=y){
fa[y]=x;ans[++ans[]]=a[i];
if(++tot==K) break;
}
}
}
inline void work(){
for(int i=num0+,x,y;i<=m;i++){
x=find(e[i].u);y=find(e[i].v);
if(x!=y){
fa[y]=x;ans[++ans[]]=i;
if(++tot==n-) break;
}
}
}
inline void print(){
for(int i=;i<=ans[];i++) z[i]=e[ans[i]];
sort(z+,z+ans[]+,cmp);
for(int i=;i<=ans[];i++) printf("%d %d %d\n",z[i].u,z[i].v,z[i].w);
}
void dfs(int x){
if(x>K){
ord();work();
if(tot==n-){print();exit();}
return ;
}
for(int i=a[x-]+;i<=num0;i++){
if(!vis[i]){
vis[i]=;
a[x]=i;
if(num0-i<K-x) break;
dfs(x+);
vis[i]=;
a[x]=;
}
}
}
int main(){
// freopen("sh.txt","r",stdin);
srand(time());
n=read();m=read();K=read();
for(int i=;i<=m;i++){
e[i].u=read(),e[i].v=read(),e[i].w=read(),e[i].id=i;
if(!e[i].w) num0++;
}
sort(e+,e+m+,cmp2);
if(K<=){dfs();puts("no solution");return ;}
while(){
pre();
if(tot!=n-) work();
if(tot==n-){print();return ;}
if(++cct==) break;
}
puts("no solution");
// cnt=ans[0];ans[0]=0;
// for(int i=1;i<=ans[0];i++) printf("%d %d %d\n",e[ans[i]].u,e[ans[i]].v,e[ans[i]].w);
/*for(int i=1;i<=cnt;i++) z[i]=e[ans[i]];
sort(z+1,z+cnt+1,cmp2);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1,tot=0,x,y;i<=cnt;i++){
x=find(z[i].u);y=find(z[i].v);
if(x!=y){
fa[y]=x;ans[++ans[0]]=i;
if(++tot==n-1) break;
}
}*/
/*cnt=ans[0];ans[0]=0;
for(int i=1;i<=cnt;i++) e[i]=z[ans[i]];
sort(e+1,e+cnt+1,cmp);*/
// for(int i=1;i<=cnt;i++) printf("%d %d %d\n",e[i].u,e[i].v,e[i].w);
return ;
}

代码留念

自己的第二次思路:(后悔当时为什么没有多想想)
  2次kruscal解决。
  第一次kruscal:首先考虑把所有水泥路连上。如果构不成树,则需要用鹅卵石路填边,这些鹅卵石路是必须要的鹅卵石路(如果必须要的鹅卵石路的数量>K直接无解);剩下的鹅卵石路都是不必要的。
  第二次kruscal:先把上一次找到的必须要的鹅卵石路填上,此时的鹅卵石路不一定恰有K条,可能比K条少,于是考虑优先连不必要的鹅卵石路,直到凑满K条为止,然后剩下的边随便找几条水泥路连起来就好(special judge告诉我们输出任意解均可)

ps:

  边权只有01的图,生成树的权值和可以取到任意的介于[MST,MBT]的任意值,其中MST表示最小生成树,MBT最大。

  我们可以发现MST和MBT的区别在与其中一些点,这些点与生成树联通的边可以选择0或者1,所以你可以把一些点的边替换,每次权值变化1,所以可以取到任意的权值.

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=4e4+;
const int M=2e5+;
struct edge{int u,v,w,tag;}e[M];
int n,m,K,tot,fa[N];
inline int read(){
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void ReadData(){
n=read();m=read();K=read();
for(int i=;i<=m;i++) e[i].u=read(),e[i].v=read(),e[i].w=read(),e[i].tag=;
}
inline void Kruscal1(){
int cct=;
for(int i=;i<=n;i++) fa[i]=i;
for(int i=,x,y;i<=m;i++) if(e[i].w){//先铺水泥路
x=find(e[i].u);y=find(e[i].v);
if(x!=y){
fa[y]=x;
if(++cct==n-) break;
}
}
if(cct==n-) return ;
for(int i=,x,y;i<=m;i++) if(!e[i].w){
x=find(e[i].u);y=find(e[i].v);
if(x!=y){
fa[y]=x;tot++;e[i].tag=;//必要鹅卵石
if(++cct==n-) break;
}
}
}
inline void Kruscal2(){
int cct=;
for(int i=;i<=n;i++) fa[i]=i;
for(int i=,x,y;i<=m;i++) if(e[i].tag){//整理找出的必要鹅卵石
x=find(e[i].u);y=find(e[i].v);
if(x!=y){
fa[y]=x;
if(++cct==n-) break;
}
}
for(int i=,x,y;i<=m;i++) if(!e[i].w){
x=find(e[i].u);y=find(e[i].v);
if(x!=y){
fa[y]=x;++cct;e[i].tag=;//不必要鹅卵石补齐K条
if(++tot==K) break;
}
}
if(tot!=K){puts("no solution");exit();}
for(int i=,x,y;i<=m;i++) if(e[i].w){//水泥路补齐n-1条
x=find(e[i].u);y=find(e[i].v);
if(x!=y){
fa[y]=x;e[i].tag=;
if(++cct==n-) break;
}
}
}
inline void WriteAns(){
for(int i=;i<=m;i++) if(e[i].tag) printf("%d %d %d\n",e[i].u,e[i].v,e[i].w);
}
int main(){
ReadData();
Kruscal1();
Kruscal2();
WriteAns();
return ;
}

[Apio2008]免费道路[Kruscal]的更多相关文章

  1. 题解 Luogu P3623 [APIO2008]免费道路

    [APIO2008]免费道路 题目描述 新亚(New Asia)王国有 N 个村庄,由 M 条道路连接.其中一些道路是鹅卵石路,而其它道路是水泥路.保持道路免费运行需要一大笔费用,并且看上去 王国不可 ...

  2. [BZOJ3624][Apio2008]免费道路

    [BZOJ3624][Apio2008]免费道路 试题描述 输入 输出 输入示例 输出示例 数据规模及约定 见“输入”. 题解 第一步,先尽量加入 c = 1 的边,若未形成一个连通块,则得到必须加入 ...

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

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

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

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

  5. P3623 [APIO2008]免费道路

    3624: [Apio2008]免费道路 Time Limit: 2 Sec Memory Limit: 128 MBSec Special Judge Submit: 2143 Solved: 88 ...

  6. Kruskal算法及其类似原理的应用——【BZOJ 3654】tree&&【BZOJ 3624】[Apio2008]免费道路

    首先让我们来介绍Krukal算法,他是一种用来求解最小生成树问题的算法,首先把边按边权排序,然后贪心得从最小开始往大里取,只要那个边的两端点暂时还没有在一个联通块里,我们就把他相连,只要这个图里存在最 ...

  7. [APIO2008]免费道路

    [APIO2008]免费道路 BZOJ luogu 先把必须连的鹅卵石路连上,大于k条no solution 什么样的鹅卵石路(u,v)必须连?所有水泥路都连上仍然不能使u,v连通的必须连 补全到k条 ...

  8. [APIO2008]免费道路(生成树)

    新亚(New Asia)王国有 N 个村庄,由 M 条道路连接.其中一些道路是鹅卵石路,而其它道路是水泥路.保持道路免费运行需要一大笔费用,并且看上去 王国不可能保持所有道路免费.为此亟待制定一个新的 ...

  9. 【bzoj3624】Apio2008—免费道路

    http://www.lydsy.com/JudgeOnline/problem.php?id=3624 (题目链接) 题意 给出一张无向图,其中有0类边和1类边.问能否构成正好有K条0类边的生成树, ...

随机推荐

  1. 深入理解Java虚拟机(一)

    一.运行时数据区域 ​ 1.程序计数器: 当前线程执行字节码的行号指示器(通过改变计数器的值来选择下条需要执行的字节码指令) 每个线程有独立的程序计数器(线程私有,为了切换线程时能恢复到挣钱的执行位置 ...

  2. level 6 - unit 2 - 情态动词May

    情态动词May 正式的请求/许可 意思为可以 例如我们在机场候机室听广播的时候,在播报航班前经常听到: may i have your attention ,please ! (请注意听) 在机场过安 ...

  3. php解析mpp文件中的多级任务

    获取层级的project任务  参考 启动javabridge java -jar JavaBridge.jar SERVLET_LOCAL:8089 1.读取mpp文件 $file_path = & ...

  4. ambari hdp 集成 impala

    1.下载ambari-impala-service VERSION=`hdp-select status hadoop-client | sed 's/hadoop-client - \([0-9]\ ...

  5. python类和模块区别,python命名空间

    在python中,类可以提供模块级别之下的命名空间. 如果一个模块写很多函数,某些函数之间共同完成一组功能,用类会看起来更清晰,在调用时候也会更好,对于ide补全有更小范围的限定提示. 类提供 继承 ...

  6. uwsgi部署web,error while loading shared libraries: libpython2.7.so.1.0: cannot open shared object file: No such file or directory

    使用的是miniconda2安装的python,并且加入了环境变量,可是uwsgi部署web时候仍然报错error while loading shared libraries: libpython2 ...

  7. actor binary tree lab4

    forward 与 ! (tell) 的差异,举个例子: Main(当前actor): topNode ! Insert(requester, id=1, ele = 2) topNode: root ...

  8. python中安装dlib和cv2

    这两个模块是很容易出问题的模块,以下的解决办法都是从网上收集而来. 安装dlib: pypi.python.org/pypi/dlib/19.6.0 下载 dlib-19.6.0-cp36-cp36m ...

  9. 屏蔽win10中文输入法

    Windows 10自带的默认输入法,是通过Shift键来切换中/英文,这样为玩一些不需要打字,却需要使用Shift键的游戏带来了不便,比如,在进行游戏的时候,按下Shift键后,再按跳跃.射击等键, ...

  10. iOS 严重问题解释(crash)

    问题1:Exception Type: 00000020 Exception Codes: 0x000000008badf00d Exception Note: SIMULATED (this is  ...