问题

  图像的数字表达是由r行s列的数字所组成的二维矩阵(二维数组)。矩阵(数组)中每个值的取值范围为[0,255]。>图像的数字表达是由r行s列的数字所组成的二维矩阵(二维数组)。矩阵(数组)中每个值的取值范围为[0,255]。

  图像压缩需要将所有数据排成一行,比如将第2行接在第1行之后,第i+1行接到第i行之后,得到数字序列p1,p2,...,pn。用二进制数来表示pi,得到图像编码。因为pi取值范围为[0,255],所以可以用8位二进制来表示pi,比如0000011001011011表示第一数字为6,第二个数字为91.

  如果每个数字都用8位来表示的话,太浪费空间了。比如240,190,255,130,5,4,7,6,3,5这十个数,如果每个数字都用8位来表示的话,需要80位存储空间。如果将前4个作为一组用8位来表示,后6个为一组用3位来表示,同时在每一组的开头加上这一组所用的位数(第一组为8)和长度(第一组为4),则可以节省空间。假定长度不超过255(即需要8位表示长度),位数不超过8(8只需要3位表示),所以每一组的开头需要加上11位。在本例中,存储空间为11+48+11+63=72位,显然比80位节约空间。

代码

#define _CRT_SECURE_NO_WARNINGS
#include <iostream> 
using namespace std;

long long length(int i);
void Compress(int n, int p[], int s[], int l[], int b[]);
//void Tracebace(int n, int& i, int s[], int l[]);
int a = 0;

void Compress(int n, int p[], int s[], int l[], int b[])
{
    int Lmax = 255, header = 11;
    s[0] = 0;

    //将存入的数字逐一取出
    for (int i = 1; i <= n; i++)
    {

        b[i] = length(p[i]);//当前数的位数
        int bmax = b[i];

        s[i] = s[i - 1] + bmax;//记录
        l[i] = 1;

        for (int j = 2; j <= i && j <= Lmax; j++)
        {
            //筛选出最大长度(即与上一次状态的数值的长度比较)
            if (bmax < b[i - j + 1])
            {
                bmax = b[i - j + 1];
            }

            //开始累加数 当位数不足时也按照最大长度来表示
            if (s[i] > s[i - j] + j * bmax)
            {
                s[i] = s[i - j] + j * bmax;
                l[i] = j;//记录当前状态位数最大值位置(即分段位置)
            }
        }
        s[i] += header;
    }
}

//转二进制数长度
long long length(int i)
{
    int k = 1;
    i = i / 2;
    while (i > 0)
    {
        k++;
        i = i / 2;
    }
    return k;
}

//void Traceback(int n, int& i, int s[], int l[])
//{
//    if (n == 0)
//        return;
//    Traceback(n - l[n], i, s, l);
//    s[i++] = n - l[n];
//}

int main()
{
    int n;
    scanf("%d", &n);
    n += 1;
    int* s = new int[n];
    int* l = new int[n];
    int* b = new int[n];
    int* p = new int[n];

    p[0] = 0;
    for (int i = 1; i < n; i++) {
        scanf("%d", &p[i]);
    }
    Compress(n - 1, p, s, l, b);
    cout << s[n - 1] << endl;
    return 0;
}

样例

输入

  • 第一行为一个数n。 第二行为n个数,分别为p1,...,pn
10
240 190 255 130 5 4 7 6 3 5

输出

72
最后修改:2022 年 09 月 19 日
如果觉得我的文章对你有用,请随意赞赏