题目链接:

IOI2018highway

题目大意:给出一张$n$个点$m$条边的无向图,并给出一对未知的起点和终点,每条边都有两种边权$A$和$B$(每条边的$A$和$B$都分别相同),每次你可以设置每条边的边权并向交互库询问,交互库会返回给你当前边权下起点到终点的最短路,你需要在不多于$50$次的询问后找出起点和终点。

我们设起点为$S$,终点为$T$。

首先需要一次询问将边权都设为$A$来知道$S$到$T$的最短路。然后我们可以用二分来找到一个处于$S$到$T$最短路上的点:每次将编号在$[0,mid]$的点的所有出边设为$B$,其他的设为$A$。如果得到的最短路不变,那么显然编号在$[mid+1,n-1]$的点有处于$S$到$T$最短路上的点,反之编号在$[0,mid]$的点有处于$S$到$T$最短路上的点。我们设找到的这个点为$x$,那么$S$与$T$中一定有一个点距离$x$较远,我们设这个点为$S$。从$x$开始$bfs$,二分然后每次将$bfs$序的$[mid+1,n-1]$这些点的所有出边设为$B$,其他边设为$A$,这样就能找到$S$,再从$S$开始$bfs$同样二分$bfs$序找到$T$。这样询问次数是$3*log_{2}^{90000}+1=52$,可以得到$90$分。

既然第一步可以二分找到最短路上的一个点,那么我们同样也可以找到一条边。每次将编号在$[0,mid]$的边设为$B$其他边设为$A$来找到最短路上的一条边,对于这条边的两端点$(u,v)$显然每个点到这两个点的最短距离不同,我们按每个点到这两个点的最短距离将离$u$更近的分为一部分,离$v$更近的分为另一部分,对于每部分还是二分$bfs$序来分别找到$S$和$T$,这样最坏情况询问次数为$1+log_{2}^{130000}+2*log_{2}^{45000}=50$,即可得到满分。

  1. #include"highway.h"
  2. #include<queue>
  3. #include<cstdio>
  4. #include<vector>
  5. #include<algorithm>
  6. #define ll long long
  7. using namespace std;
  8. vector<int>s[90010];
  9. vector<int>to[90010];
  10. int w[130010];
  11. ll path;
  12. queue<int>q;
  13. int dis_u[90010];
  14. int dis_v[90010];
  15. int que_u[90010];
  16. int que_v[90010];
  17. int cnt_u;
  18. int cnt_v;
  19. int S,T;
  20. bool cmp_u(int x,int y)
  21. {
  22. return dis_u[x]<dis_u[y];
  23. }
  24. bool cmp_v(int x,int y)
  25. {
  26. return dis_v[x]<dis_v[y];
  27. }
  28. void find_pair(int n,vector<int> u,vector<int> v,int A,int B)
  29. {
  30. int num=u.size();
  31. for(int i=0;i<num;i++)
  32. {
  33. s[u[i]].push_back(i);
  34. to[u[i]].push_back(v[i]);
  35. s[v[i]].push_back(i);
  36. to[v[i]].push_back(u[i]);
  37. }
  38. path=ask(vector<int>(w,w+num));
  39. int l=0;
  40. int r=num-1;
  41. while(l<r)
  42. {
  43. int mid=(l+r)>>1;
  44. for(int i=0;i<num;i++)
  45. {
  46. w[i]=0;
  47. }
  48. for(int i=0;i<=mid;i++)
  49. {
  50. w[i]=1;
  51. }
  52. ll value=ask(vector<int>(w,w+num));
  53. if(value==path)
  54. {
  55. l=mid+1;
  56. }
  57. else
  58. {
  59. r=mid;
  60. }
  61. }
  62. q.push(u[l]);
  63. dis_u[u[l]]=1;
  64. while(!q.empty())
  65. {
  66. int now=q.front();
  67. q.pop();
  68. int len=to[now].size();
  69. for(int i=0;i<len;i++)
  70. {
  71. if(!dis_u[to[now][i]])
  72. {
  73. dis_u[to[now][i]]=dis_u[now]+1;
  74. q.push(to[now][i]);
  75. }
  76. }
  77. }
  78. q.push(v[l]);
  79. dis_v[v[l]]=1;
  80. while(!q.empty())
  81. {
  82. int now=q.front();
  83. q.pop();
  84. int len=to[now].size();
  85. for(int i=0;i<len;i++)
  86. {
  87. if(!dis_v[to[now][i]])
  88. {
  89. dis_v[to[now][i]]=dis_v[now]+1;
  90. q.push(to[now][i]);
  91. }
  92. }
  93. }
  94. for(int i=0;i<n;i++)
  95. {
  96. if(dis_u[i]<dis_v[i])
  97. {
  98. que_u[++cnt_u]=i;
  99. }
  100. else
  101. {
  102. que_v[++cnt_v]=i;
  103. }
  104. }
  105. sort(que_u+1,que_u+1+cnt_u,cmp_u);
  106. sort(que_v+1,que_v+1+cnt_v,cmp_v);
  107. l=1,r=cnt_u;
  108. while(l<r)
  109. {
  110. int mid=(l+r)>>1;
  111. for(int i=0;i<num;i++)
  112. {
  113. w[i]=0;
  114. }
  115. for(int i=mid+1;i<=cnt_u;i++)
  116. {
  117. int len=s[que_u[i]].size();
  118. for(int j=0;j<len;j++)
  119. {
  120. w[s[que_u[i]][j]]=1;
  121. }
  122. }
  123. ll value=ask(vector<int>(w,w+num));
  124. if(path==value)
  125. {
  126. r=mid;
  127. }
  128. else
  129. {
  130. l=mid+1;
  131. }
  132. }
  133. S=que_u[l];
  134. l=1,r=cnt_v;
  135. while(l<r)
  136. {
  137. int mid=(l+r)>>1;
  138. for(int i=0;i<num;i++)
  139. {
  140. w[i]=0;
  141. }
  142. for(int i=mid+1;i<=cnt_v;i++)
  143. {
  144. int len=s[que_v[i]].size();
  145. for(int j=0;j<len;j++)
  146. {
  147. w[s[que_v[i]][j]]=1;
  148. }
  149. }
  150. ll value=ask(vector<int>(w,w+num));
  151. if(path==value)
  152. {
  153. r=mid;
  154. }
  155. else
  156. {
  157. l=mid+1;
  158. }
  159. }
  160. T=que_v[l];
  161. answer(S,T);
  162. }

[IOI2018]高速公路收费——二分查找+bfs的更多相关文章

  1. HDU 5652 India and China Origins 二分优化+BFS剪枝

    题目大意:给你一个地图0代表可以通过1代表不可以通过.只要能从第一行走到最后一行,那么中国与印度是可以联通的.现在给你q个点,每年风沙会按顺序侵蚀这个点,使改点不可通过.问几年后中国与印度不连通.若一 ...

  2. jvascript 顺序查找和二分查找法

    第一种:顺序查找法 中心思想:和数组中的值逐个比对! /* * 参数说明: * array:传入数组 * findVal:传入需要查找的数 */ function Orderseach(array,f ...

  3. Java实现的二分查找算法

    二分查找又称折半查找,它是一种效率较高的查找方法. 折半查找的算法思想是将数列按有序化(递增或递减)排列,查找过程中采用跳跃式方式查找,即先以有序数列的中点位置为比较对象,如果要找的元素值小 于该中点 ...

  4. 从一个NOI题目再学习二分查找。

    二分法的基本思路是对一个有序序列(递增递减都可以)查找时,测试一个中间下标处的值,若值比期待值小,则在更大的一侧进行查找(反之亦然),查找时再次二分.这比顺序访问要少很多访问量,效率很高. 设:low ...

  5. java实现二分查找

    /** * 二分查找 * @param a * @param n * @param value * @return * @date 2016-10-8 * @author shaobn */ publ ...

  6. 最新IP地址数据库 二分逼近&二分查找 高效解析800万大数据之区域分布

    最新IP地址数据库  来自 qqzeng.com 利用二分逼近法(bisection method) ,每秒300多万, 比较高效! 原来的顺序查找算法 效率比较低 readonly string i ...

  7. c#-二分查找-算法

    折半搜索,也称二分查找算法.二分搜索,是一种在有序数组中查找某一特定元素的搜索算法. A 搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束: B 如果某一特定元素大于或者小 ...

  8. 【Python】二分查找算法

    二分查找:在一段数字内,找到中间值,判断要找的值和中间值大小的比较.如果中间值大一些,则在中间值的左侧区域继续按照上述方式查找.如果中间值小一些,则在中间值的右侧区域继续按照上述方式查找.直到找到我们 ...

  9. PHP实现文本快速查找 - 二分查找

    PHP实现文本快速查找 - 二分查找法 起因 先说说事情的起因,最近在分析数据时经常遇到一种场景,代码需要频繁的读某一张数据库的表,比如根据地区ID获取地区名称.根据网站分类ID获取分类名称.根据关键 ...

随机推荐

  1. vue-amap 实例获取与自动缩放

    this.$refs.map.$amap.setFitView(markers) 获取实例,$amap 为 el-map 的 vid,没错,vid 获取方式就是这样 markers 为 Amap.Ma ...

  2. 讲一个关于paxos的故事...

    先讲一个故事. 从前,在国王Leslie Lamport的统治下,有个黑暗的希腊城邦叫paxos.城邦里有3类人, 决策者 提议者 群众 虽然这是一个黑暗的城邦但是很民主,按照议会民主制的政治模式制订 ...

  3. vue 饿了么项目笔记

    vue 饿了么项目 1.图标字体引用 链接 2.scss 二三倍图切换 1像素边框 链接 3.better-scroll 4.布局 商品主页面 <div id="app"&g ...

  4. os.path 下的各方法

    一.os.path os.path.abspath(file) #拿到当前程序(文件)的绝对目录. os.path.split(pathname) # 返回一个元组,第零个元素为文件上级绝对目录,第一 ...

  5. Python_面向对象基础

    概念 类 一类抽象的事物,是描述了一类事物有哪些属性或者行为,但不是具体——模子. 实例 一个依托于类的规范存在的,被赋予了具体属性值的实际存在的物体. 对象 就是实例,实例的另外一个名称,相当于别名 ...

  6. WPF中定时器Timer与DispatcherTimer的用法

    最近的工作项目中需要定时更新UI控件中的数据,这时候第一反应肯定会想到去使用System.Timers.Timer定时更新UI控件,但是程序运行后,会发现程序崩溃了.报的异常为“调用线程无法访问此对象 ...

  7. Html5使用canvas作图

    以下例子是项目中实际用到的.不足之处请大家指正,设计到画线,写文字,填充,文字旋转. <!DOCTYPE html> <html> <head lang="en ...

  8. Azure系列1.1.2 —— 用于 IntelliJ 的 Azure 工具包的登录说明

    (文中大部分内容(95%)Azure官网上有,我只是把我自己实际操作中遇到的问题在这里阐述一下.) 先决条件 若要完成文章中的步骤,需要安装用于 IntelliJ 的 Azure 工具包,该工具包需要 ...

  9. Windows 机器上面同时安装mysql5.6 和 mysql5.7 的方法

    1. 自己遇到的两个坑: . mysql 登录的时候 需要使用-P 来指定端口号 不然默认走 呢 . mysql 5.6 和 mysql 5.7 更改用户密码的命令不一样.. 我这边浪费了很长时间: ...

  10. Mybatis Dao层注解及XML组合Dao的开发方式

    mybatis可以用xml进行数据操作,也可以在dao层用注解的方式,也可以采取xml和dao层接口组合使用的方法.显然 ,后者更加简单. 实体类Student   package com.zhao. ...