文章目录

  • 一、题目描述
  • 二、解题思路
    • 1. 定义状态
    • 2. 定义状态转移方程
    • 3. 初始化
    • 4. 计算方式
  • 三、代码实现
  • 四、执行结果
  • 五、思考

一、题目描述

​ 计算机中的图像由一系列像点构成,每个像点称为一个像素,图像分辨率越高,使用的像素就越多,例如Windows桌面的图片经常使用的设置是1024×768个,大概达到106量级.图像传输和视频处理有时在1秒钟内要处理几十帧图片,这些图片的像素就很可观了,因此图像处理常常需要大量的存储空间和高的处理速度,图像压缩问题就成了计算机科学技术中的重要研究课题之一.

​ 以黑白图像的处理来说明图像压缩中的问题.每幅黑白图像由像点构成,每个像点具有灰度值,用0~255之间的整数表示.如果每个整数都用相同的二进制位来表示,那么需要用8个二进制位.假设一幅图像有n个像素,那么这n个像素的灰度值构成一个整数序列:P = <p1,p2,…,pn>

​ 其中p表示第i个像素的灰度.存储这幅图片时,可以像数组一样连续把这些整数存起来,共需要8n个二进制位.

​ 下面考虑一种图像压缩方法.一般来说,在一幅图片中许多连续区域中像点的灰度值是接近的.比如有些交通标志图片,大片的区域是白的,可能少量区域有颜色,而且是比较单调的颜色.对这样的图片是否可以采用分段存储的方法:对灰度值较小的段的像素采用比较少的位数,比如2位;对灰度值较大的段的像素采用较多的位数,比如8位,这样就可能减少空间的占用.这就是变位压缩技术的基本想法.这种技术节省了空间,但在读取图像时带来了新的问题.在每个像素8位的存储方法中,读取图像时每8位就是一个像素的灰度值,不会出错.但是对于分段压缩的图像,看起来就是一个长长的0-1序列.当读取这个序列时,怎么知道每段的划分位置及每段像素占用的二进制位数呢?这里需要对段的划分和段中像素使用的二进制位数(要求同一段内不同像素用的存储位数都一样)给出明确的信息.为此,我们对每个段给出两个整数值,一个表示该段含有的像素个数,一个表示每个像素所占用的二进制位数.比如第i段,有l[i]个像素,每个像素用b[i]位.由于某些技术要求,规定每段像素总数不超过256,即l[i]≤256.于是可以用8位来表示l[i](8位二进制数恰好有256个值).此外,由于每个灰度值在0~255之间,表达每个灰度值所用二进制数的位数b[i]不超过8,于是记录b[i]还需要3个二进制位.对每段来说,这额外的11位作为段头信息.从直觉上来说,分段越多,每段内部像素所占用的位数会减少,但过多的段头会消耗较多的二进制位.相反,分段越少,段内像素的空间消耗会增加,但是段头消耗少.

示例:

​ 请看下面的例子.设输入的灰度值序列是:

​ P =<10,12,15,255,1,2,1,1,2,2,1,1>

  • 分法1 S1= <10,12,15>,S2 =<255>,S3=<1,2,1,1,2,2,1,1>

  • 分法2 S1=<10,12,15,255,1,2,1,1,2,2,1,1>

  • 分法3 S1=<10>,S2=<12>,S3=<15>,S4=<255>,S5=<1>,S6=<2>,S7=<1>,S8=<1>,S9=<2>,S10=<2>,S11=<1>,S12=<1>

    ​ 分法1有3段,第1段3个像素,每个像素用4位;第2段1个像素,每个像素用8位;第3段8个像素,每个像素用2位;加上3个段头,每个段头11位,总计位数是:
    4×3+8×1+2×8+3×11=69

    ​ 分法2有1段,12个像素,每个像素用8位,段头11位,总计位数是:
    8×12+11=107

    ​ 分法3有12段,前3段的像素用4位,第4段像素用8位,后面有5段像素用1位,3段像素用2位,还有12个段头,每个11位,总计位数是:
    4×3+8×1+1×5+2×3+11×12=163

    看起来分法1占用的位数最少.我们的问题是寻找存储位数最少的分段方法.

二、解题思路

1. 定义状态

​ 设dp[i]表示字符串前i个像素点的保存的最少二进制数的数量,i从1开始计数,那么我们最终要求出的是dp[P.length]即为像素序列P的最少消耗空间;

​ 假设每个分段数量为j,则由于题目约束可得1≤j<=min(i,256)1 \leq j <=min(i,256)1≤j<=min(i,256), 假设像素序列i的后j个像素序列分为一段,则有dp[i] = dp[i - j] + j x log2max(Pi-j+1,…,Pi) + 11 ,当然j值可能有多个,我们取最小花费那个。

2. 定义状态转移方程

当1≤j<=min(i,256)1 \leq j <=min(i,256)1≤j<=min(i,256),有

​ dp[i]=min(dp[i−j]+j×log2max(Pi−j+1,..,Pi)+11)dp[i] = min(dp[i - j] + j \times log_2max(P_{i-j+1},..,P_i) + 11) dp[i]=min(dp[i−j]+j×log2​max(Pi−j+1​,..,Pi​)+11)

3. 初始化

​ 当 i = 0时,有dp[0]=0dp[0] = 0dp[0]=0

4. 计算方式

​ 自左向右计算

三、代码实现

/*** 最优图像压缩位数**  @author hh*  @date 2021-5-21 21:46*/
public class OptimalImageCompression {public int optimalBits(int[] dots,int[] traces){int[] dp = new int[dots.length + 1];int cost = Integer.MAX_VALUE;//初始化行dp[0] = 0;for(int i = 1; i <= dots.length; i++){dp[i] = Integer.MAX_VALUE;for(int j = 1; j <= Math.min(i,256); j++){cost = dp[i -j] + j * (this.minBits(this.max(dots,i -j + 1,i))) +11;if(cost < dp[i]){dp[i] = cost;traces[i] = j;}}}return dp[dots.length];}public void print(int[] traces, int length){length -= traces[length];if(length <= 0){return;}print(traces,length);System.out.print(length + " ");}private int max(int[] dots,int start,int end){int[] copy =  Arrays.copyOfRange(dots,start -1,end);Arrays.sort(copy);return copy[copy.length -1];}private int minBits(int number){int bits = 0;for(int i = 1; i <= 8; i++){if(Math.pow(2,i-1) - 1 <= number && Math.pow(2,i) - 1 >= number){bits = i;break;}}return bits;}public static void main(String[] args){int[] dots = new int[]{10,12,15,255,1,2,1,1,2,2,1,1};int[] traces = new int[dots.length + 1];OptimalImageCompression optimalImageCompression = new OptimalImageCompression();System.out.println("最少二进制位:" + optimalImageCompression.optimalBits(dots,traces));System.out.print("切分位置:");optimalImageCompression.print(traces,dots.length);}
}

四、执行结果

五、思考

​ 本题和文本压缩的做法非常相似,都是对dp数组进行线性划分,读者有时间可以看我的另一篇文章动态规划经典题目-数据压缩之文本压缩,进行举一反三。

动态规划经典题目-数据压缩之图像压缩相关推荐

  1. 动态规划经典题目_动态规划经典题目:鸡蛋掉落(附视频讲解)

    题目: 思路: 先放上视频讲解 动态规划经典题目:鸡蛋掉落https://www.zhihu.com/video/1225199247848513536 纠正:视频里的状态转移方程漏写了一个+1,意思 ...

  2. 动态规划经典题目-最小权三角剖分

    文章目录 一.题目描述 二.解题思路 1. 定义状态 2. 定义状态转移方程 3. 初始化 4. 计算方式 三.代码实现 四.执行结果 五.思考 一.题目描述 设A是顶点为0,1,-,n-1的n凸多边 ...

  3. 动态规划经典题目——最大子矩阵和

    一.题目 题目描述:现给出一个N*N矩阵,要求求出拥有最大和的子矩阵的和.例子如下图所示: 它的最大子矩阵的和为15: 二.解题思路 此题的解法与动态规划经典题目--最大连续子序列之和题目思想一样,只 ...

  4. 动态规划经典题目整理

    动态规划经典题目整理 背包问题 最长公共子串问题 连续数组最大和问题 持续增加中.... 背包问题 复杂度 O(nW)O(nW)O(nW) nnn为物品种类,WWW是背包的重量 目的:使得背包中的物品 ...

  5. poj动态规划经典题目

    列表一:经典题目题号: 容易: 1018, 1050, 1088, 1125, 1143, 1157, 1163, 1178, 1179, 1189, 1191,1208, 1276, 1322, 1 ...

  6. 动态规划经典题目总结

    微信公众号 在算法中,动态规划题目算是比较经典的一类题目.在找工作中,不管是笔试,还是面试,我们经常会遇到用动态规划来解决问题的情况,有时候面试官还需要我们现场手写出动态规划解法的代码.因此,在求职中 ...

  7. 动态规划经典题目汇总

    http://www.cppblog.com/doer-xee/archive/2009/12/05/102629.html 转载之前先Orz一下: [s:19] Robberies http://a ...

  8. 动态规划经典题目——数塔问题

    一.题目 数塔问题 :要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少? 二.解题思路 动态规划解题思路可详见另一篇文章.数塔中元素用二维数组a[][]表示 ①定义状态 ...

  9. 动态规划经典题目——0-1背包

    一.题目 有N件物品和一个容量为V的背包.第i件物品的重量是w[i],价值是v[i].求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大. 二.解题思路 动态规划解题思路可详见 ...

最新文章

  1. jQuery之validate验证表单
  2. 电子自动窗帘系统c语言程序,单片机自动窗帘控制程序(两个电机)
  3. 百度定位SDK的使用示例
  4. 【Luogu】P3950部落冲突(树链剖分)
  5. 矩形波如何傅立叶展开_金科文化会不会连续拉板?两位同学展开激辩
  6. php数组基础知识,PHP 数组基础知识小结
  7. 添加库文件_PLC|教你把 Micro/WIN 的库文件导入到 Micro/WIN SMART 中
  8. 鸿蒙 自研内核 core b,华为平板将首次搭载鸿蒙OS 2.0系统:首次自研内核与构架...
  9. 3140: [Hnoi2013]消毒
  10. CRACK秘籍之爆破
  11. win7修复计算机消失,详细教您win7 aero效果消失了怎么恢复
  12. cs1.6联机服务器没有响应,cs1.6联机问题解说
  13. qt qtableview 刷新列表_qt qtableview基本用法
  14. 如何查看某台计算机的IP地址 物理地址,显示ip:如何查看电脑ip地址和物理地址(地址)? _ 惠州SEO...
  15. Python制作经典坦克大战小游戏
  16. SpringBoot生命周期
  17. java左移和右移_java 位运算 之 左移和右移理解
  18. IKBC键盘Win键失效的解决办法
  19. EQS(场景查询系统)
  20. 雷军:把UCWEB做成像GOOGLE一样伟大

热门文章

  1. 作业2:BP 算法实验报告
  2. 计算机不能切换显卡,“双显卡电脑,开机windows启动画面过后黑屏,切换显卡无效”的解决方案...
  3. 超越Facebook!特斯拉市值破万亿美元,马斯克身价近3000亿美元稳坐全球首富
  4. 68家信托公司7大派系股东分食图谱
  5. MBSE建模学习之一:说说模块(Block)
  6. 通过Gitee克隆仓库加速GitHub下载
  7. sql等值连接,左右连接
  8. Android 实现蓝牙打印的功能
  9. FJNU2019级第二场排位赛D题Nim题解
  10. 数据分析不再是热门职位,而是必备技能