1246: 图像压缩
时间限制: 1 Sec 内存限制: 128 MB
提交: 1295 解决: 692
[提交] [状态] [讨论版] [命题人:外部导入]
题目描述
图像压缩的问题我们是这样理解的:大家都知道计算机的图像是用灰度值序列来表示的{P1,P2......Pn},其中Pi表示像素点i的灰度值。而通常灰度值的范围是0~255,因此需要8位二进制数来表示一个像素。这个时候大家应该有了一些小的疑问:我能不能用更少的位数来表示灰度值?(因为有的灰度值并没有达到255这么大)所以我们引入了图像压缩算法来解决这个问题。
把序列{p1,p1,……pn}进行设断点,将其分割成一段一段的。每一段的最大灰度值既代表了这一段的像素,这样就可以节约存储空间。但需要注意每段最多包含255个像素点。
我们用l[i]表示每段里面有多少个像素点,最多为255个(即8位二进制);b[i]表示每段一个像素点需要的存储空间,最多为8(即3位二进制)。则为了存储每一个分段,另需要(8+3)=11的代价。
输入
第一行一个整数n代表n个像素点(1<=n<=5000)。
第二行n个整数分别代表像素点的灰度值。
输出
输出图像最少需要多少存储空间。
样例输入 Copy
7 4 6 5 7 129 138 1
样例输出 Copy
58
提示
样例的解释
以下的压缩方式为最优压缩方式
4 6 5 7 为一组,最大值为7需要3位二进制表示,所以压缩后需要的空间12+11=23
129 138 1为一组,最大
import java.util.Scanner;
//1246
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] pixels = new int[n];
for (int i = 0; i < n; i++) {
pixels[i] = scanner.nextInt();
}
System.out.println(minimumStorageSpace(n, pixels));
scanner.close();
}
private static int minimumStorageSpace(int n, int[] pixels) {
int[] dp = new int[n + 1];
for (int i = 0; i <= n; i++) {
dp[i] = Integer.MAX_VALUE;
}
dp[0] = 0;
for (int i = 1; i <= n; i++) {
int maxGrey = 0;
for (int j = i; j <= Math.min(n, i + 254); j++) {
maxGrey = Math.max(maxGrey, pixels[j - 1]); // pixels[j-1] because j is 1-indexed in dp
int segmentLength = j - i + 1;
int bitsNeeded = bitsNeeded(maxGrey);
int storageCost = segmentLength * bitsNeeded + 11;
if (dp[i - 1] != Integer.MAX_VALUE && dp[i - 1] + storageCost < dp[j]) {
dp[j] = dp[i - 1] + storageCost;
}
}
}
return dp[n];
}
private static int bitsNeeded(int maxGrey) {
if (maxGrey == 0) return 1;
return 32 - Integer.numberOfLeadingZeros(maxGrey);
}
}
值为138需要8位二进制表示,所以压缩后需要的空间为24+11=35