图像压缩的动态规划算法

思路

目测这个题也是最优子结构问题,首先就是查找到当前数组中最优的切割点,然后进行切割,进入下一轮循环。

递推公式如下:
s [ i ] = m i n 1 ≤ k ≤ m i n { i , 256 } { s [ i − k ] + k × b m a x ( i − k + 1 , i ) } + 11 s[i]=min_{1\le k \le min\{i,256\}} \{ s[i-k] + k\times b max(i-k+1, i) \}+11 s[i]=min1kmin{i,256}{s[ik]+k×bmax(ik+1,i)}+11
其中:
b m a x ( i , j ) = ⌈ l o g ( m a x i ≤ k ≤ j ( p k ) + 1 ) ⌉ b max(i,j)=\lceil log(max_{i\le k \le j} (p_k) +1 ) \rceil bmax(i,j)=log(maxikj(pk)+1)

代码

import java.util.Arrays;

/**
 * @author: 
 * @description: 图像压缩的动态规划算法
 * @date: Created in 2020/4/16 0:05
 * @ersion: 1.0
 */
public class Work8 {

    public Work8(){

        int[] img = { 1, 10, 12, 255, 255, 1, 2, 1, 1, 2, 2, 1, 1 };

        System.out.println( compImg(img) );
    }

    /**
    * 将输入的数组进行切割
    *
    * @param image 一个一维数组
    * @return 返回拆分后的数组的长度
    * */
    public int compImg( int[] image ){

        //长度为零时返回结果,0
        if ( image.length < 1 ){
            return 0;
        //长度为一时,返回这个数的长度加11
        }else if ( image.length == 1 ){
            System.out.println( image[0] );
            return 11+Integer.toString( image[0], 2 ).length();
        }

        //用于存储image数组中每个空隙左右两侧的数的最长长度,len[0]存储左侧len[1]存储右侧
        int[][] len = new int[image.length-1][2];

        //首先将首尾的特殊情况进行处理
        len[0][0] = Integer.toString( image[0], 2 ).length();
        len[len.length-1][1] = Integer.toString( image[image.length-1], 2 ).length();

        //暂存当前未分割情况下的数组的最长值,也是当前未分割情况下,数组每个单元需要的存储空间
        int maxlen = Math.max( len[0][0], len[len.length-1][1] );

        //对len数组进行赋值,并得到maxlen的值
        //每次循环,只需要对当前值和前一个值进行比较,取最大值即可
        //左侧最大值,从左向右遍历得到,右侧最大值由右至左遍历得到
        for ( int i = 1, j = len.length-2; i < len.length; i++, j-- ){

            int tmp = Integer.toString( image[i], 2 ).length();
            len[i][0] = Math.max(len[i-1][0], tmp );
            maxlen = Math.max( maxlen, tmp );

            tmp = Integer.toString( image[j+1], 2 ).length();
            len[j][1] = Math.max(len[j+1][1], tmp );
            maxlen = Math.max( maxlen, tmp );
        }

        //数组最小所占空间
        int sum = 11 + maxlen*(len.length+1);
        //存储分割的位置,如果可以进行分割的话
        int index = -1;

        //遍历数组,得到最适合的切割位置
        for ( int i = 0; i < len.length; i++ ){
            int tmp = len[i][0]*(i+1) + len[i][1]*(len.length-i-1) + 22;

            if ( tmp < sum ){
                index = i;
                sum = tmp;
            }
        }

        //根据index的值,判断是否可以进行分割
        //如果不行就输出结果,如果可以分隔就将数组进行切割,进入下一次循环
        if ( index == -1 ){
            for ( int i : image ){ System.out.print( i + "\t "); }
            System.out.println( "sum:" + sum );
            return sum;
        }else {
            return compImg(Arrays.copyOfRange( image, 0, index+1)) + compImg(Arrays.copyOfRange( image, index+1, image.length));
        }
    }

    public static void main(String[] args) {
        Work8 work8 = new Work8();
    }
}

你可能感兴趣的:(算法,笔记)