抛玻璃算法

下面为例子来源;

网上闲逛,看到一算法题大体如下:

有一幢100层高的大楼,给你两个完全相同的玻璃棋子。
假设从某一层开始,丢下玻璃棋子就会破碎。那么怎么利用手中的两颗棋子,
用一种什么样的最优策略,知道这个临界的层高呢?

 

  大致想了下... 得出的第一个算法是33  66  99 

  IF( 既第一个Q从33楼扔,如果碎了. 就从第一层向33层枚举..) 

   {

    假设最糟糕的情况是32楼是临界点.

     33楼 + 1 + 2 +3 ....... +32  =  33次...  嗯...上下楼33,累死了... 

 }

else

  IF(33楼扔下去没碎,那么从66楼往下扔)

       最糟糕的情况又发生了 =.=!   65层才是临界点.那么...

     33层 + 66层 + (34---65)  =33次 ..............!!!  

   如果66没碎...  99也没碎.. 那么就是 33 + 66 + 99 + (67--98 ) = 34次..

 脑袋里反映出来的第一个算法,, 最糟糕的情况要扔 33或者34次..  效率显然不高..

 

看了下回帖,有个叫IToa什么的同志... 贴出了他的算法..

   第一次从15层往下扔..碎了的话,, 最糟糕 15 + (1-13) = 14次.

  没碎继续: 第二次从(15-1)+15 = 29 层往下扔.  碎了为: 15 + 29 + (16 ---28)= 14次

         第三次 (14 - 1) + 29  = 42   碎了的话 最多也是跑上14次而已... 

   该算法最糟糕的情况为14次或者13次就能得出临界点,,效率显然比我高的多..

  毕竟. 我是菜鸟.. 哈哈哈哈

 

  还有的人的算法是 以10为单位扔玻璃球... 那么结果是: 10,10, 11 .12.13.14.15.16.17.18.

      显然,,15-1的这种算法比较均衡,从头到位都是13或者14... 而以10为单位的这种算法前期比较有效...

     但在临界点==99层的情况,,要测18次才行..

  而前一种算法则无论临界点在那层..都只要14次就能完成............    

 

      仔细思考后,,发现第一种算法仍然不是最有效的...

     10 23(10+15-2) 35(23+15-3)............ 100

   该算法扔玻璃球的效率为 10 13 13 13.........12 

   既

    int n,s,L ;

   L = 100 ; //楼层 

    n=sqrt(L) ;   //给该楼开方==10     =.=!

      s= n+ sqrt(n);  // 继续开方得到计算差值

    while(n<=L)

      {n = n + (n+s--); // 循环计算直到开关为假, >楼层数

     ................ //设置好临界点,满足临界点后标记然,退出循环; }

 

 

 到网络上搜索了一下..有段不知出处的C++代码.

 里面用暴力穷举出的最佳点是:9 22 34 45 55 64 72 79 85 90 94 97 99 100

        9为开端,偶的是10为开端... 其后都是15-(2++)

 第一部比偶的快了一点点.. 哈哈哈哈  次数是: 9 13 13 13..........12 

  但偶的算法适用于各种高度的楼层..只是两次开方,循环计算<sqrt(楼层高度)

  对方的是暴力破解... 如果楼层过高...嗯嗯,家用计算机可能需要数年才能计算出来

   

没有最高效,只有更高效....继续学习ing..........


【以上来自:http://blog.csdn.net/Estel/archive/2007/02/07/1504840.aspx

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1504840 

我的解法为:

      我是这么考虑的,要采用最小的代价找出摔碎玻璃球的方法,那么首先要区分区间,即摔碎球的区间在哪儿?
因为在每一层都有可能,那么应该是符合平均分布规律的,也就是说我们只要将区间分析正确了,那么得到应该为最佳的方案。
      只有两个球,那么我们只能先通过摔碎玻璃球来确定在哪个区间中,然后逐层往上摔球。
接下来该分区间了,该怎么分呢?显然有以下关系式:
                                    前面区间的个数+当前区间中的数目<=某一个值M
      因此问题就转换为求出“某一个值M的问题了,因为当这个值求出之后,开始时前面区间的个数为0个,从数学上讲是一个递推的关系式。
     我们可以推测,除了首和尾之外,中间区间必然要满足:
                                  前面区间个数+当前区间中的数目=某一个值M
     设当前区间为第i个区间,那么前面有i-1个区间,而当前区间的个数为:M-i-1 (>=0),其应该满足下面一个关系式:
                                 ∑(M-i-1)<L(层数) i从1到last-1,其中i=last<M
      最佳的区间分配显然为last+1=M,即最末尾只有一个数的时候。
由此可以推断的层数为(逆向排列):
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,……
       当层数为100时,(1+区间个数)*区间个数/2 < 100,即所有区间个数之和小于总的层数。
于是计算得到区间个数为:13。
也就是说层的个数为:
1,2,3,4,5,6,7,8,9,10,11,12,13
因此排列方式为:
100,99,97,94,90,85,79,72,64,55,45,34,22,9
至此,解答完毕!

希望能有更好的算法(不同思想上的)……

python3 glasswindow.py [ WARN:0@1.737] global loadsave.cpp:275 findDecoder imread_('window_scene.jpg'): can't open/read file: check file path/integrity [ WARN:0@1.737] global loadsave.cpp:275 findDecoder imread_('depth_map.png'): can't open/read file: check file path/integrity Traceback (most recent call last): File "/home/realsense-d455-test/glasswindow.py", line 84, in <module> glass_mask, frame_lines, result_img = detect_glass_and_frame(rgb_img, depth_map) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/realsense-d455-test/glasswindow.py", line 41, in detect_glass_and_frame gray = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cv2.error: OpenCV(4.12.0) /home/conda/feedstock_root/build_artifacts/libopencv_1753287227905/work/modules/imgproc/src/color.cpp:199: error: (-215:Assertion failed) !_src.empty() in function 'cvtColor' 请根据上面报错提示修改下面的代码,并提供一份完整的代码 import cv2 import numpy as np import matplotlib.pyplot as plt def detect_glass_and_frame(rgb_img, depth_map): """ 检测玻璃及窗框的核心函数 参数: rgb_img: RGB彩色图像 (H, W, 3) depth_map: 深度图 (H, W),无效值通常为0 返回: glass_mask: 玻璃区域掩膜 frame_lines: 检测到的窗框线段 result_img: 可视化结果图像 建议: 在强光照环境下,为深度相机添加红外滤光片 对窗框线段进行聚类和延长处理,形成完整框架 使用RANSAC算法拟合更精确的直线方程 """ # ===== 1. 深度图预处理 ===== # 创建玻璃候选区域掩膜(深度值为0的区域) glass_mask = np.where(depth_map == 0, 255, 0).astype(np.uint8) # 形态学操作优化掩膜 kernel = np.ones((5, 5), np.uint8) glass_mask = cv2.morphologyEx(glass_mask, cv2.MORPH_CLOSE, kernel) # 闭运算填充空洞 glass_mask = cv2.dilate(glass_mask, kernel, iterations=2) # 扩大边缘区域 # 中值滤波降噪 glass_mask = cv2.medianBlur(glass_mask, 5) # ===== 2. 玻璃区域分割 ===== # 查找轮廓并过滤小区域 contours, _ = cv2.findContours(glass_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) min_area = 1000 # 最小面积阈值 glass_roi = np.zeros_like(glass_mask) for cnt in contours: area = cv2.contourArea(cnt) if area > min_area: cv2.drawContours(glass_roi, [cnt], -1, 255, -1) # ===== 3. 窗框检测 ===== # RGB图像预处理 gray = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY) clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8)) enhanced = clahe.apply(gray) # 边缘检测(在玻璃区域边界) edges = cv2.Canny(enhanced, 50, 150) # 霍夫变换检测直线 lines = cv2.HoughLinesP(edges, rho=1, theta=np.pi/180, threshold=50, minLineLength=100, maxLineGap=10) # 几何约束筛选窗框线 frame_lines = [] if lines is not None: for line in lines: x1, y1, x2, y2 = line[0] # 筛选水平/垂直线(角度容差±10度) if abs(x1 - x2) < 10 or abs(y1 - y2) < 10: frame_lines.append(line[0]) # ===== 4. 结果可视化 ===== result_img = rgb_img.copy() # 绘制玻璃区域(半透明红色) glass_color = np.zeros_like(rgb_img) glass_color[glass_roi == 255] = [0, 0, 255] # 红色 cv2.addWeighted(glass_color, 0.3, result_img, 1, 0, result_img) # 绘制窗框线 for line in frame_lines: x1, y1, x2, y2 = line cv2.line(result_img, (x1, y1), (x2, y2), (0, 255, 0), 2) return glass_roi, frame_lines, result_img # ===== 主程序 ===== if __name__ == "__main__": # 模拟数据加载(实际使用时应替换为真实相机数据) # 注意:实际应用中需使用pyrealsense2等库获取深度相机数据 rgb_img = cv2.imread('window_scene.jpg') # 替换为实际RGB图像路径 depth_map = cv2.imread('depth_map.png', cv2.IMREAD_ANYDEPTH) # 替换为实际深度图路径 # 执行检测 glass_mask, frame_lines, result_img = detect_glass_and_frame(rgb_img, depth_map) # 显示结果 plt.figure(figsize=(15, 10)) plt.subplot(221) plt.title("RGB Image") plt.imshow(cv2.cvtColor(rgb_img, cv2.COLOR_BGR2RGB)) plt.subplot(222) plt.title("Depth Map") plt.imshow(depth_map, cmap='jet') plt.colorbar() plt.subplot(223) plt.title("Glass Detection") plt.imshow(glass_mask, cmap='gray') plt.subplot(224) plt.title("Detection Result") plt.imshow(cv2.cvtColor(result_img, cv2.COLOR_BGR2RGB)) plt.tight_layout() plt.show()
最新发布
07-31
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值