- 浏览: 533065 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (231)
- 一个操作系统的实现 (20)
- 汇编(NASM) (12)
- Linux编程 (11)
- 项目管理 (4)
- 计算机网络 (8)
- 设计模式(抽象&封装) (17)
- 数据结构和算法 (32)
- java基础 (6)
- UML细节 (2)
- C/C++ (31)
- Windows (2)
- 乱七八糟 (13)
- MyLaB (6)
- 系统程序员-成长计划 (8)
- POJ部分题目 (10)
- 数学 (6)
- 分布式 & 云计算 (2)
- python (13)
- 面试 (1)
- 链接、装载与库 (11)
- java并行编程 (3)
- 数据库 (0)
- 体系结构 (3)
- C++ template / STL (4)
- Linux环境和脚本 (6)
最新评论
-
chuanwang66:
默默水塘 写道typedef void(*Fun)(void) ...
C++虚函数表(转) -
默默水塘:
typedef void(*Fun)(void);
C++虚函数表(转) -
lishaoqingmn:
写的很好,例子简单明了,将观察者模式都表达了出来。
这里是ja ...
观察者模式——Observer
二分答案
如果已知候选答案的范围[min,max],有时候我们不必通过计算得到答案,只需在此范围内应用“二分”的过程,逐渐靠近答案(最后,得到答案)!
一、何时可以使用“二分答案”
不是任何题目都适合使用“二分答案”的,我Sam观察到一般有以下的一些特征:
A. 候选答案必须是离散的
,且已知答案的范围是:[最小值min, 最大值max]
(连续区间上不能进行二分操作)
例如,在题目“Kth Largest 第k大的数”中 ==> 答案是闭区间[a[1]b[1], a[n]b[n]]上的正整数
例如,在题目“Drying 烘干衣服”中 ==> 烘干时间t∈[0,maxT], maxT=max{a[i]}
B. 候选答案在区间[min,max]上某种属性一类一类的排列
(这样就能在此属性上进行二分操作
),各个类别不交错混杂
例如,在题目“Kth Largest 第k大的数”中 ==>
(候选答案)第k大的数的值: a[1]b[1], ... , a[n]b[n]
(属性分类)>这个乘积的数有多少: n^2-1 ... 0
例如,在题目“Drying 烘干衣服”中 ==>
(候选答案)烘干时间: t=0, t=1, t=2, t=3, ..., t=maxT-1, t=maxT
(属性分类)能否烘干: 不能 不能 不能 能 ... 能 能
C. 容易判断某个点
是否为答案(即二分过程中,mid指向的点是否为答案)
例如,在题目“Kth Largest 第k大的数”中 ==> λ∈[ a[1]b[1], a[n]b[n] ]
对于某个候选答案,如果“>λ的乘积个数"<k && “>λ-1的乘积个数”≥k ,则答案为λ
例如,在题目“Drying 烘干衣服”中 ==>
需要寻找第一个出现的“能”(true),即如果check(mid-1)==false && check(mid)==true ,则答案为mid.
----------------------------------------------------------------------------------------------------------------------------------
二、举例
例一、Kth Largest 第k大的数
题目来源: http://acm.hrbeu.edu.cn/index.php?act=problem&id=1211
TimeLimit: 1 Second MemoryLimit: 32 Megabyte
Description
There are two sequences A and B with N (1<=N<=10000) elements each. All of the elements are positive integers. Given C=A*B, where '*' representing Cartesian product, c = a*b, where c belonging to C, a belonging to A and b belonging to B. Your job is to find the K'th largest element in C, where K begins with 1.
Input
Input file contains multiple test cases. The first line is the number of test cases. There are three lines in each test case. The first line of each case contains two integers N and K, then the second line represents elements in A and the following line represents elements in B. All integers are positive and no more than 10000. K may be more than 10000.
Output
For each case output the K'th largest number.
Sample Input
2
2 1
3 4
5 6
2 3
2 1
4 8
Sample Output
24
8
【题解】:直接二分答案,然后判断答案的正确性。
假设当前二分的答案为 t,那么:
对于ai <= t的衣服,显然让它们自然风干就可以了。
对于ai > t的衣服,我们需要知道该衣服最少用多少次烘干机。
设该衣服用了x1分钟风干,用了x2分钟烘干机。
那么有 x1 + x2 = t 和 ai <= x1 + x2 * k,联立两式可得 x2 >= (ai - t) / (k - 1),即最少使用次数为[(ai - t) / (k - 1)] 的最小上界。
最后,判断一下总使用次数是否少于 t 即可。
【题解二】双重二分。先对两个序列A,B从大到小排序,然后可以我们进行第一重二分:对要求取的答案二分,即求取的答案在[A[n]*B[n],A[1]*B[1]]之间,取s1=A[n]*B[n],e1=A[1]*B[1],mid=(s1+e1)/2,那么我们去计算在序列C中大于等于这个mid值的个数是多少,当然不是算出这个序列来,而是进行第二次二分。我们对于两个序列可以这样处理,枚举序列A,二分序列B,也就是说对于每个A[i],我们去二分序列B,来计算大于等于mid值的个数。那么我们可以得到结束条件,当大于等于mid值的个数大于等于k,且大于mid值的个数小于k,那么答案就是这个mid。那么时间复杂度就为n*log(n)*log(n^2)了。
代码:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<iostream> #include<queue> #include<map> #include<vector> #include<algorithm> using namespace std; /*测试用例: 3 4 1 1 2 3 4 5 6 7 8 4 2 1 2 3 4 5 6 7 8 4 3 1 2 3 4 5 6 7 8 */ #define maxn 10010 int cases; //用例 # int a[maxn],b[maxn]; //a[], b[] int n; //a[]和b[]的长度 int k; //对于每个测试用例,找到第 k大的答案 int ans; //答案 int cmp(const void *a,const void *b){ return *(int *)b - *(int *)a; } //对于a[i],统计a[i]*b[1], a[i]*b[2], ... , a[i]*b[n]中 >t的乘积的个数 int find(int t,int ai){ int num=0; int s=1; int e=n; int mid; while(s<=e) { mid=(s+e)>>1; if(ai*b[mid]>t){ //此时, a[i]*b[1], a[i]*b[2], ... , a[i]*b[mid]都 >t num=mid; s=mid+1; } else e=mid-1; } return num; } //统计>t的个数 int count(int t){ int i,res=0; for(i=1;i<=n;i++){//枚举A中的每一个数字 res+=find(t , a[i]); //对于a[i],二分序列 b[1]~b[n],find >t 的乘积个数 } return res; } /* 已知答案取值范围,二分枚举答案: 答案取值范围是[ s=a[n]b[n],e=a[1]b[1] ],在这个范围内找到第k大的数 a[i]b[j] */ void solve(int s,int e){ int mid=(s+e)>>1,t1,t2; while(s<=e) { mid=(s+e)>>1; t1=count(mid);//统计大于mid值的个数 [mid+1,∞) t2=count(mid-1);//统计大于等于mid值的个数 [mid,∞) if( t1<k && t2>=k ){//找到答案 ans=mid; return; } else if(t2<k) e=mid-1; else s=mid+1; } } int main(){ int i,j; scanf("%d",&cases); while(cases--) { scanf("%d%d",&n,&k); for (i = 1; i <= n; i++) scanf("%d", &a[i]); for (i = 1; i <= n; i++) scanf("%d", &b[i]); qsort(&a[1], n, sizeof(a[0]), cmp); //从大到小排列 a[] qsort(&b[1], n, sizeof(b[0]), cmp); ans=0; solve(a[n] * b[n], a[1] * b[1]); printf("%d\n", ans); } system("pause"); return 0; }
例二、POJ 3104 Drying 烘干衣服
题目来源: http://poj.org/problem?id=3104
代码:
#include<cmath> #include<iostream> using namespace std; int n; //衣服件数 int water[100010]; //水分 int k; //烘干机一次烘掉的水分 int t=-1; //最终答案:所有衣服干完的最少时间 int maxT=-1; //所有衣服干完最长用时 //用时不超过mid (<=mid)能否烘干衣服, T=O(n) bool check(int mid){ /* 若某件衣服 i水分water[i]<mid,可以自然风干;否则需要烘。 假设这件衣服自然风干用时 t1, 烘烤用时 t2. (1) t1+t2 = mid (2) t1+k*t2 >= water[i] ∴ t2 >= (water[i]-mid)/(k-1) 只需要判断使用烘干机的时间和是否 <= mid 即可 */ double radTime=0; //使用烘干机的总时间 for(int i=0;i<n;i++){ if(water[i]>mid){ radTime += ceil( (double)(water[i]-mid)/(double)(k-1) ); //衣服 a[i]需要烘的次数 } //???1. ceil()函数 } if(radTime<=mid) return true; else return false; } //所有衣服干完最少时间:[0,maxT], 二分答案 , T=O(log(maxT))O(n) void solve(){ int l=0; int r=maxT; int mid=(l+r)>>1; //mid是在“二分答案 ”过程中每次观察的答案 //???2. 在二分查找中总结这种变形的二分查找: false, false, false, ..., false, true, true, ..., true // 找第一个出现的 true 的位置 while(l<=r){ //每次进入循环,总能保证最终答案 t∈[l,r] if(check(mid)==true){ if(check(mid-1)==false){//再少用1个单位的时间都不能烘干 t=mid; //最终答案:最少用时mid return; } r=mid-1; }else{ l=mid+1; } mid=(l+r)>>1; } } int main(void){ scanf("%d",&n); //???3. 看scanf() //while(n>0){ //输入 int res=0; for(int i=0;i<n;i++){ scanf("%d", &water[i]); maxT=maxT>water[i]?maxT:water[i]; } scanf("%d",&k); //计算 & 输出 solve(); printf("%d\n",t); //scanf("%d",&n); //} system("pause"); return 0; }
发表评论
-
快排备忘
2013-10-26 11:27 547http://hi.baidu.com/pluto455988 ... -
LRU简单实现C++
2013-10-17 10:52 3970页面置换算法: 在地址映射过程中,若在页面中发现所要访问的页 ... -
二叉树相关
2013-10-04 17:40 690本节主要是为了写二叉树类型题目练手的代码,重点培养运用“指针 ... -
双指针策略(《编程之美》3.5 最短摘要生成)
2013-03-26 15:17 2221本文源自《编程之美》3.5 最短摘要生成一课。 ... -
K-MEDOIDS聚类算法
2012-12-04 21:18 1935k-medoids聚类算法 (wiki上讲得很清楚啊:) ) ... -
搜索(三)——回溯
2012-11-23 15:23 1023一、回溯 和 深度搜索 ... -
哈希Hash
2012-11-21 14:42 974要点一:哈希表长度 的确定是个两难的问题:太短则容 ... -
状态压缩DP
2012-11-14 20:27 729引例、 例1、 例2、 例3、 ... -
模拟退火
2012-10-28 16:34 1199引用:http://www.cnblogs.com/heaad ... -
计算几何(一)——基础算法
2012-07-12 21:07 1903待续 《计算几何资料》为提纲 1. (1) 有向线段 ... -
计算几何(二)——平面最近点对
2012-07-12 10:54 885参考资料: 为何这个问题采用分治法 http://blog ... -
气泡滚大——剔除线性数据中的杂质
2012-06-18 09:43 940这是一道Java的面试题,但是我总结了除了一种自称为“ ... -
P问题、NP问题和NPC问题
2012-04-25 16:36 1046这篇文章转自这里 ... -
RMQ(Range Minimum/Maximum Query)区间最值查询
2012-04-18 20:47 1543一、RMQ问题描述 和 几种解题思路 RMQ问题 (Rang ... -
后缀数组
2012-04-16 09:49 1492一、后缀数组 及其对应的名次数组 举例:S=&quo ... -
大整数运算(部分转载)
2012-04-12 21:36 1170待补充:“浮点数高精度运算” 参见这里==> ... -
单向链表相关
2012-04-10 16:42 953单向链表是微软笔试常考的,参考这里:http://www.c ... -
关键路径(AOE)
2012-04-10 08:05 1648前面这段话是引用别人的,后面代码是自己写的,有待完善: ... -
搜索(二)——双向BFS
2012-03-24 17:18 2999参考这篇文章,以下前 ... -
搜索(一)——剪枝
2012-03-24 11:46 1533参考文档:《搜索方法 ...
相关推荐
NULL 博文链接:https://chuanwang66.iteye.com/blog/1416430
二分查找和27.移除元素,记录了详细的题目解析思路以及Java语言的参考代码。 适合人群:学习算法和数据结构的程序员或学生,想要通过LeetCode来提高编程能力的人。 能学到什么:掌握二分查找算法的实现原理;了解双...
顺序查找法每一次比较,只将查找范围减少1,而二分法查找,每比较一次,可将查找范围减少为原来的一半,效率大大提高。 对于长度为n的有序线性表,在最坏情况下,二分法查找只需比较log2n次, 二级公共...
本文是深入理解javascript作用域系列第二篇——词法作用域和动态作用域 词法作用域 第一篇介绍过,编译器的第一个工作阶段叫作分词,就是把由字符组成的字符串分解成词法单元。这个概念是理解词法作用域的基础 ...
通过提供C/C++语言的算法描述,用简单的算法例子实现诸如快速排序,冒泡排序,二分查找等算法,来引导大家深入理解算法。
递归 一个函数在执行过程中一次或多次调用其本身便是递归,就像是俄罗斯套娃一样,一个娃娃里包含另一个娃娃。... 二分查找,对有序列表进行查找,如果找到则返回True,否则返回False if low > high
本书通过大量的图示和实例,深入浅出的介绍了Linux的基本原理和应用。主要包括Linux的基本概念和操作,Linux的树型结构,Linux的文本编辑,Linux的安装和启动,用户管理,Shell编程技术,进程管理,C编译器,系统...
二叉树是一种常用的数据结构,更是实现众多算法的一把利器...二分搜索树(Binary Search Tree)做为一种能实现快速定位查找的二叉树也得到了广泛应用(底层实现可参考《用一个图书库实例搞懂二分搜索树的底层原理》)。
第11章至第16章结合实际问题,继续讨论了若干几何算法及其数据结构,包括高维凸包、空间二分及BSP树、运动规划、网格生成及四叉树、最短路径查找及可见性图、单纯性区域查找及划分树和切分树等,这些也是对前10章...
题目覆盖了从基础的字符串和列表操作到更高级的算法和数据结构应用,例如滑动窗口技术、二分查找等。每个题目均附有详细的题目描述、输入输出说明、解题思路以及示例代码,旨在提供全面而深入的学习和练习体验。 ...
二分查找 : 二叉排序树,AVL树,B-,B+ : O(1) 图结构: (对象和指针,矩阵,邻接表) 图搜索/遍历: DFS BFS : kruskal prim : Floyd,Dijkstra,bellman-ford,SPFA,A* Knuth-Morris-Pratt Boyer-Moore 参考资料 基础 《算法...
尽管学生们发来了大量的请求,希望我们提供思考题和练习的解答,但我们还是决定不提供思考题和练习的参考答案,以彻底打消学生们试图查阅答案、而不是自己动手得出答案的念头。 第2版中所做的修改 在本书的第1版和...
(后续我会每天找时间补充)链表链表双向链表哈希表/散列表 (Hash Table)散列函数碰撞解决排序算法冒泡排序插入排序选择排序希尔排序快排归并排序堆排序查找算法有序表查找:二分查找哈希表: O(1)推荐书籍...
由于没有系统的学习,肯定会遇到各种各样的拦路虎问题,当遇到不懂的概念时,利用百度/谷歌查阅相关资料去理解学习这个概念,若是概念难懂,就多看不同的人对这些概念的理解,有的时候有些人能深入浅出的讲解一些很...
简介: C语言是编程语言中的一朵奇葩,虽已垂垂老矣,但却屹立不倒,... 时间复杂度、冒泡排序法、选择排序法、快速排序法、归并排序法、顺序排序法、二分查找等常用算法的详细讲解; 良好的编码习惯和编程风格。
C语言是编程语言中的一朵奇葩,虽已垂垂老矣,但却屹立不倒,诞生了... 时间复杂度、冒泡排序法、选择排序法、快速排序法、归并排序法、顺序排序法、二分查找等常用算法的详细讲解; 良好的编码习惯和编程风格。