首先让我们来介绍Krukal算法,他是一种用来求解最小生成树问题的算法,首先把边按边权排序,然后贪心得从最小开始往大里取,只要那个边的两端点暂时还没有在一个联通块里,我们就把他相连,只要这个图里存在最小生成树我们就一定可以找到他。(证明:首先如果我们没有选最小的边,那么他一定可以踢掉其他的边来使生成树更小,于是最小一定取,那么接下来能取的边同理,以此类推我们证毕。)

这个算法其实不要紧,但是他这种利用边的置换的思想,与得到最小生成树的定性,才是我们真正的收获。

【BZOJ 3654】tree

这道题在思路上还是很清晰的,他保证存在了,那么我们就是找最小的就可以。那么我们先把边排序,跑Kruskal,然后通过二分给白边加权,然后再求最小生成树,慢慢使我们的白边树逼近需要就是了,因为他说一定存在,所以你二分到小一点就多,大一点就少的情况就可以看你取边顺序直接取一个值就好了。

  1. #include <cstdio>
  2. #include <algorithm>
  3. inline void read(int &sum){
  4. register char ch=getchar();
  5. for(sum=;ch<''||ch>'';ch=getchar());
  6. for(;ch>=''&&ch<='';sum=(sum<<)+(sum<<)+ch-'',ch=getchar());
  7. }
  8. const int N=;
  9. const int M=;
  10. struct E{
  11. int a,b,w,c;
  12. }e[M];
  13. int f[N],h[];
  14. inline int find(int x){
  15. return f[x]==x?x:(f[x]=find(f[x]));
  16. }
  17. int n,m,need;
  18. inline bool comp(E a,E b){
  19. return a.w+h[a.c]<b.w+h[b.c]||(a.w+h[a.c]==b.w+h[b.c]&&a.c<b.c);
  20. }
  21. inline int get_ans(int &get){
  22. for(int i=;i<=n;i++)f[i]=i;
  23. std::sort(e+,e+m+,comp);
  24. register int x,y,w,c,hav=,ret=,whi=;
  25. for(int i=;i<=m;i++){
  26. x=e[i].a+,y=e[i].b+,w=e[i].w,c=e[i].c;
  27. if(find(x)==find(y))continue;
  28. f[find(x)]=find(y);
  29. ret+=w+h[c],whi+=c,hav++;
  30. if(hav==n-)break;
  31. }
  32. get=hav-whi;
  33. return ret;
  34. }
  35. int main(){
  36. read(n),read(m),read(need);
  37. for(int i=;i<=m;i++)
  38. read(e[i].a),e[i].a++,read(e[i].b),e[i].b++,read(e[i].w),read(e[i].c);
  39. int mid,l=-,r=,ans,get;
  40. while(l<=r){
  41. mid=(l+r)>>,h[]=mid;
  42. int ret=get_ans(get);
  43. if(get>=need)
  44. ans=ret-need*h[],l=mid+;
  45. else r=mid-;
  46. }
  47. printf("%d",ans);
  48. return ;
  49. }

【BZOJ 3654】tree

【BZOJ 3624】[Apio2008]免费道路

这道题的思维就要比上道题,大得多。首先鹅卵石边数不够 PASS!!!,然后不联通 PASS!!!。现在我们就可以用一种特殊的方法来试图找到我们想要的边数,我们发现如果我们把水泥路分成两半,一半放在鹅卵石前(鹅卵石连续),另一半放在鹅卵石后,然后跑类Krusal(其实一样只是不是求最小),那么随着前一半长度减小,鹅卵石边数单调不减,且最小变化幅度小于等于1,所以如果存在我们一定可以找到那种方案(为什么呢,如果我们把水泥路鹅卵石路分别都视为一类,不管具体是什么,那么显然成立,那么如果我们关注他们具体是谁就要考虑到他们顺序问题,然而实际上并没有关系),如果不存在直接 PASS !!!

然而如果我们知道这个的话,就会发现,其实我们只要判断一下题目中的k在不在先鹅卵石再水泥和先水泥再鹅卵石围成的区间里就好了。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5. #define ft first
  6. #define sd second
  7. #define abs(a) ((a)<0?-(a):(a))
  8. #define mmp(a,b) std::make_pair((a),(b))
  9. typedef std::pair<int,int> pii;
  10. const int N=;
  11. const int M=;
  12. int f[N],n,m,m0,m1,k;
  13. pii use[M],ger[M],cct[M];
  14. int in[M];
  15. inline int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
  16. inline void Unit(int x,int y){f[find(x)]=find(y);}
  17. inline bool judge(){
  18. if(k>m0)return true;int ret=;
  19. for(int i=;i<=n;++i)
  20. if(find(i)==i)++ret;
  21. return ret>;
  22. }
  23. inline int check(int pos){
  24. for(int i=;i<=n;++i)f[i]=i;
  25. for(int i=;i<=pos;++i)use[i]=cct[i];
  26. for(int i=;i<=m0;++i)use[i+pos]=ger[i];
  27. for(int i=pos+;i<=m1;++i)use[m0+i]=cct[i];
  28. memset(in,-,sizeof(in));int ret=,have=;
  29. for(int i=;i<=m&&have<n;++i){
  30. if(find(abs(use[i].ft))==find(use[i].sd))continue;
  31. if(use[i].ft>)in[i]=,++ret;
  32. else in[i]=;
  33. Unit(abs(use[i].ft),use[i].sd),++have;
  34. }//printf("<%d %d>\n",pos,ret);
  35. return ret;
  36. }
  37. int main(){
  38. scanf("%d%d%d",&n,&m,&k);
  39. for(int i=;i<=n;++i)f[i]=i;
  40. for(int i=,x,y,z;i<=m;++i){
  41. scanf("%d%d%d",&x,&y,&z);
  42. if(z)cct[++m1]=mmp(-x,y);
  43. else ger[++m0]=mmp(x,y);
  44. Unit(x,y);
  45. }if(judge()){puts("no solution");return ;}
  46. int l=,r=m1,mid;
  47. bool ans=false;
  48. while(l<=r){
  49. mid=(l+r)>>;
  50. int ret=check(mid);
  51. if(ret==k){ans=true;break;}
  52. if(ret>k)l=mid+;
  53. else r=mid-;
  54. }if(!ans){puts("no solution");return ;}
  55. for(int i=;i<=m;++i)
  56. if(in[i]!=-)
  57. printf("%d %d %d\n",abs(use[i].ft),use[i].sd,in[i]);
  58. return ;
  59. }

Kruskal算法及其类似原理的应用——【BZOJ 3654】tree&&【BZOJ 3624】[Apio2008]免费道路的更多相关文章

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

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

  2. BZOJ.3624.[APIO2008]免费道路(Kruskal)

    题目链接 我们发现有些白边是必须加的,有些是多余的. 那么我们先把所有黑边加进去,然后把必须要加的白边找出来. 然后Kruskal,把必须要加的白边先加进去,小于K的话再加能加的白边.然后加黑边. 要 ...

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

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

  4. 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 这 ...

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

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

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

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

  7. bzoj 3624: [Apio2008]免费道路【生成树+贪心】

    先把水泥路建生成树,然后加鹅卵石路,这里加的鹅卵石路是一定要用的(连接各个联通块),然后初始化并查集,先把必需的鹅卵石路加进去,然后随便加鹅卵石路直到k条,然后加水泥路即可. 注意判断无解 #incl ...

  8. Dijkstra 算法、Kruskal 算法、Prim算法、floyd算法

    1.dijkstra算法 算最短路径的,算法解决的是有向图中单个源点到其他顶点的最短路径问题. 初始化n*n的数组. 2.kruskal算法 算最小生成树的,按权值加入 3.Prim算法 类似dijk ...

  9. 最小生成树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind

    最小支撑树树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind 最小支撑树树 前几节中介绍的算法都是针对无权图的,本节将介绍带权图的最小 ...

随机推荐

  1. redis搭建

    redis 1.简介.安装 Remote Dictionary Server(Redis)是一个基于 key-value 键值对的持久化数据库存储系统.redis 和 Memcached 缓存服务很像 ...

  2. Hadoop==zookeeper

    Zookeeper 每一个专业的技术总可以在生活中找到相应的实例,就比如说zookeeper,攘其外必先安其内就很好的解释了zookeeper,Hadoop集群的组件中的很多在学习的时候都会觉得每一个 ...

  3. Python正则表达式-基础

    Python正则表达式-基础 本文转载自昔日暖阳,原文地址:http://www.osheep.cn/4806.html python使用正则,需要先引入re模块 import re 匹配符 单个字符 ...

  4. Shoot the Bullet(ZOJ3229)(有源汇上下界最大流)

    描述 ensokyo is a world which exists quietly beside ours, separated by a mystical border. It is a utop ...

  5. JS正则表达式笔记

    正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串.将匹配的子串替换或者从某个串中取出符合某个条件的子串等. 正则 描述 ...

  6. PHP.45-TP框架商城应用实例-后台20-权限管理-RBAC表构造与代码生成

    权限管理 三张主表{p39_privilege(权限).p39_role(角色).p39_admin(管理)} 两张中间表{p39_role_pri(角色-权限).p39_admin_role(管理- ...

  7. MUI:字符串和json数据的相互转换

    JSON.parse()--字符串转换json.JSON.stringify()--json转换成字符串 如:收到Json对象:response,则: {"result":&quo ...

  8. 通过transpose和flip实现图像旋转90/180/270度

    在fbc_cv库中,提供了对图像进行任意角度旋转的函数rotate,其实内部也是调用了仿射变换函数warpAffine.如果图像仅是进行90度倍数的旋转,是没有必要用warpAffine函数的.这里通 ...

  9. linux安装oracle远程客户端

    文章参考:http://blog.csdn.net/caomiao2006/article/details/11901123 感谢博友分享O(∩_∩)O~ 安装oracle 远程客户端(一般情况下本地 ...

  10. 3招搞定APP注册作弊

    在说如何应对之前,易盾先给各位盾友梳理移动端APP可能遇到哪些作弊风险.1. 渠道商刷量,伪造大量的下载量和装机量,但没有新用户注册:2. 对于电商.P2P.外卖等平台,会面临散户或者团队刷子的注册- ...