将求最大的连续组合值转换为背包问题
2012-10-04 14:29
471 查看
题目:有四种面值的邮票很多枚,这4种邮票面值分别为1分,4分,12分,21分。现在从多张中最多任取5张进行组合,求出这些邮票的最大连续组合值。(这些邮票最小能表示的面值为1,那么最大连续组合值的意思是说,从1开始往下一直连续下去,当且仅当该面值能被这4种邮票表示。)
书上给了一个参考程序:
思路就是从1开始往下遍历,对于每一个数字看能不能被这4种邮票表示,知道有一个数字不能被表示,那么程序停止。
程序输出为:
1,总数为:1
1,1,总数为:2
1,1,1,总数为:3
1,1,1,1,总数为:4
1,1,1,1,1,总数为:5
1,1,4,总数为:6
1,1,1,4,总数为:7
1,1,1,1,4,总数为:8
1,4,4,总数为:9
1,1,4,4,总数为:10
1,1,1,4,4,总数为:11
4,4,4,总数为:12
1,4,4,4,总数为:13
1,1,4,4,4,总数为:14
1,1,1,12,总数为:15
............
4,4,21,21,21,总数为:71
前些天做过完全背包的问题,貌似这题可以用类似(只是说和完全背包类似,不完全一样)的方法解决。如果不清楚背包问题,可以看一下这个:http://blog.csdn.net/wangxiaolongbob/article/details/8037720
将上面的问题转化一下:
有一个背包负重为105(针对本题),现在有4个物品{1,4,12,21},每个物品的个数是无限个,求物品刚好装满背包(物品总重量为105)时的物品个数最小为多少?
当然这个问题不一定能求出来,但是当以这个问题为目标,最后遍历玩二维数组以后,那么邮票的问题也就解决了。
如上表所示,
初始化状态为全都“不能表示”。
接下来用物体1来,表示1需要1个,表示2需要2个,表示3就需要3个...他不能表示6,因为物体最多只能5个,那么后面的全是无穷大了。
接下来用4来表示,他不能表示1,2,3,只能从4开始,那么当前状态1,2,3的最优值就是前面状态的最优值,现在注意了,用4这个物体去表示4只需要1个,比前一个状态(物体1表示4需要4个)要少,那么就替换掉了。然后看用4这个物体去表示5,发现5-4=1,那么我们看第一列发现他的最优解就是1,那么5的最优解就是2了。其他的就按照这个方法填就是了,在填的时候要始终判断个数是不是大于5,如果大于5,就说明不能表示,就用无穷大表示。当我们把这个二维数组遍历完了之后,在去遍历最后一排(21这一排),直到遇到无穷大就停下来,这时结果就找到了。
当然,这个二维数组可以优化成用一维数组表示,代码如下:
package com.interview.mccv;
/**
* 最大连续组合值 Maximum continuous composite value
*
* @author xiaolong
*
*/
public class MCCV {
private int maxElementNum;// 一个组合中元素的最多个数
private int[] faceValue;// 每一个元素的价值存放在数组中
private int[] record;
private int max;// faceValue中的最大值
private int min;// faceValue中的最小值
public MCCV(int maxElementNum, int[] faceValue) {
this.maxElementNum = maxElementNum;
this.faceValue = faceValue;
initRecord();
}
private void initRecord() {
sort(faceValue);
min = faceValue[0];
max = faceValue[faceValue.length - 1];
record = new int[max * maxElementNum + 1];// 把faceValue所能表示的最大值作为背包的总负重,在这题中最大值为21*5=105
for (int i = 0; i < record.length; i++) {
record[i] = Integer.MAX_VALUE;
}
}
/**
* 对faceValue进行排序
*/
private void sort(int[] faceValue) {
int minIndex;
for (int i = 0; i < faceValue.length; i++) {
minIndex = i;
for (int j = i + 1; j < faceValue.length; j++) {
if (faceValue[j] < faceValue[minIndex])
minIndex = j;
}
if (minIndex != i)
swap(i, minIndex);
}
}
/**
* 在faceValue数组中交换下标分别为i和j的2个数的位置
*
* @param i
* @param j
*/
private void swap(int i, int j) {
int temp;
temp = faceValue[j];
faceValue[j] = faceValue[i];
faceValue[i] = temp;
}
public void start() {
int temp;
for (int i = 0; i < faceValue.length; i++) {// 遍历所有的faceValue,相当与背包问题中遍历所有的物品
for (int j = faceValue[i]; j < record.length; j++) {// 从当前物品的面值开始,一直遍历到最后。
if ((j - faceValue[i]) == 0) {
record[j] = 1;
// System.out.print(j + ":");
} else {
if ((temp = record[j - faceValue[i]]) != Integer.MAX_VALUE) {
temp++;
if (temp <= maxElementNum && temp < record[j])// 只有当当前状态比前一状态小时,才记录
record[j] = temp;
}
}
// System.out.print(record[j] + " ");
}
// System.out.println();
}
}
public int getResult() {
for (int i = min; i < record.length; i++) {
// System.out.println(record[i]);
if (record[i] == Integer.MAX_VALUE) {
return i - 1;
}
}
return 0;
}
public static void main(String[] args) {
int[] faceValue = new int[] { 1, 4, 12, 21 };
int maxElementNum = 5;
// 时间测试
long start = System.currentTimeMillis();
MCCV mccv = new MCCV(maxElementNum, faceValue);
mccv.start();
System.out.println("最大连续组合数为:" + mccv.getResult());
long end = System.currentTimeMillis();
System.out.println("MCCV time lasts " + (end - start) + "ms");
}
}
这个过程描述的比较生硬,以后要多写写了。
书上给了一个参考程序:
package com.interview.mccv; public class ProgramInbook { int num = 5; int k; boolean find; int logo[] = new int[num]; int stamp[] = { 0, 1, 4, 12, 21 }; int M = 5;// 表示stamp数组的长度 private boolean check(int n, int Value) { if (n >= 0 && Value == 0) { find = true; int sum = 0; for (int i = 0; i < num && logo[i] != 0; i++) { sum += stamp[logo[i]]; // System.out.print(Stamp[Logo[i]] + ","); } // System.out.println("总数为:" + Sum); } else for (int i = 1; i < M && !find && n > 0; i++) if (Value - stamp[i] >= 0) { logo[k++] = i; check(n - 1, Value - stamp[i]); logo[--k] = 0; } return find; } public int getResult() { int i; for (i = 1; check(num, i); i++, find = false) ; return i - 1; } public static void main(String[] args) { // 时间测试 long start = System.currentTimeMillis(); ProgramInbook program = new ProgramInbook(); System.out.println(program.getResult()); long end = System.currentTimeMillis(); System.out.println("ProgramInbook time lasts " + (end - start) + "ms"); } }
思路就是从1开始往下遍历,对于每一个数字看能不能被这4种邮票表示,知道有一个数字不能被表示,那么程序停止。
程序输出为:
1,总数为:1
1,1,总数为:2
1,1,1,总数为:3
1,1,1,1,总数为:4
1,1,1,1,1,总数为:5
1,1,4,总数为:6
1,1,1,4,总数为:7
1,1,1,1,4,总数为:8
1,4,4,总数为:9
1,1,4,4,总数为:10
1,1,1,4,4,总数为:11
4,4,4,总数为:12
1,4,4,4,总数为:13
1,1,4,4,4,总数为:14
1,1,1,12,总数为:15
............
4,4,21,21,21,总数为:71
前些天做过完全背包的问题,貌似这题可以用类似(只是说和完全背包类似,不完全一样)的方法解决。如果不清楚背包问题,可以看一下这个:http://blog.csdn.net/wangxiaolongbob/article/details/8037720
将上面的问题转化一下:
有一个背包负重为105(针对本题),现在有4个物品{1,4,12,21},每个物品的个数是无限个,求物品刚好装满背包(物品总重量为105)时的物品个数最小为多少?
当然这个问题不一定能求出来,但是当以这个问题为目标,最后遍历玩二维数组以后,那么邮票的问题也就解决了。
如上表所示,
初始化状态为全都“不能表示”。
接下来用物体1来,表示1需要1个,表示2需要2个,表示3就需要3个...他不能表示6,因为物体最多只能5个,那么后面的全是无穷大了。
接下来用4来表示,他不能表示1,2,3,只能从4开始,那么当前状态1,2,3的最优值就是前面状态的最优值,现在注意了,用4这个物体去表示4只需要1个,比前一个状态(物体1表示4需要4个)要少,那么就替换掉了。然后看用4这个物体去表示5,发现5-4=1,那么我们看第一列发现他的最优解就是1,那么5的最优解就是2了。其他的就按照这个方法填就是了,在填的时候要始终判断个数是不是大于5,如果大于5,就说明不能表示,就用无穷大表示。当我们把这个二维数组遍历完了之后,在去遍历最后一排(21这一排),直到遇到无穷大就停下来,这时结果就找到了。
当然,这个二维数组可以优化成用一维数组表示,代码如下:
package com.interview.mccv;
/**
* 最大连续组合值 Maximum continuous composite value
*
* @author xiaolong
*
*/
public class MCCV {
private int maxElementNum;// 一个组合中元素的最多个数
private int[] faceValue;// 每一个元素的价值存放在数组中
private int[] record;
private int max;// faceValue中的最大值
private int min;// faceValue中的最小值
public MCCV(int maxElementNum, int[] faceValue) {
this.maxElementNum = maxElementNum;
this.faceValue = faceValue;
initRecord();
}
private void initRecord() {
sort(faceValue);
min = faceValue[0];
max = faceValue[faceValue.length - 1];
record = new int[max * maxElementNum + 1];// 把faceValue所能表示的最大值作为背包的总负重,在这题中最大值为21*5=105
for (int i = 0; i < record.length; i++) {
record[i] = Integer.MAX_VALUE;
}
}
/**
* 对faceValue进行排序
*/
private void sort(int[] faceValue) {
int minIndex;
for (int i = 0; i < faceValue.length; i++) {
minIndex = i;
for (int j = i + 1; j < faceValue.length; j++) {
if (faceValue[j] < faceValue[minIndex])
minIndex = j;
}
if (minIndex != i)
swap(i, minIndex);
}
}
/**
* 在faceValue数组中交换下标分别为i和j的2个数的位置
*
* @param i
* @param j
*/
private void swap(int i, int j) {
int temp;
temp = faceValue[j];
faceValue[j] = faceValue[i];
faceValue[i] = temp;
}
public void start() {
int temp;
for (int i = 0; i < faceValue.length; i++) {// 遍历所有的faceValue,相当与背包问题中遍历所有的物品
for (int j = faceValue[i]; j < record.length; j++) {// 从当前物品的面值开始,一直遍历到最后。
if ((j - faceValue[i]) == 0) {
record[j] = 1;
// System.out.print(j + ":");
} else {
if ((temp = record[j - faceValue[i]]) != Integer.MAX_VALUE) {
temp++;
if (temp <= maxElementNum && temp < record[j])// 只有当当前状态比前一状态小时,才记录
record[j] = temp;
}
}
// System.out.print(record[j] + " ");
}
// System.out.println();
}
}
public int getResult() {
for (int i = min; i < record.length; i++) {
// System.out.println(record[i]);
if (record[i] == Integer.MAX_VALUE) {
return i - 1;
}
}
return 0;
}
public static void main(String[] args) {
int[] faceValue = new int[] { 1, 4, 12, 21 };
int maxElementNum = 5;
// 时间测试
long start = System.currentTimeMillis();
MCCV mccv = new MCCV(maxElementNum, faceValue);
mccv.start();
System.out.println("最大连续组合数为:" + mccv.getResult());
long end = System.currentTimeMillis();
System.out.println("MCCV time lasts " + (end - start) + "ms");
}
}
这个过程描述的比较生硬,以后要多写写了。
相关文章推荐
- 有限制的最大连续和问题
- 最大连续子串问题
- uva 242 DP 求s张邮票可以连续组合成最大面值多少的邮票
- 输出1到N之间所有相加等于M的数字组合(背包问题)求相加为M的所有组合--微软酷派经典面试题
- HDU 1864(最大报销额)基础0-1背包问题
- 编程求解,输入两个整数n和m,从数列1,2,3,……n中随意取几个数,使其和等于m。要求将所有的可能组合列出来(背包问题求解)
- 最大子矩阵问题;枚举行的组合,然后利用一维最大子段和的DP算法;
- 求和最大的连续子序列问题分…
- 求整数m的最大加数为n的组合问题
- 最大连续邮资问题的JAVA实现
- [背包DP] 背包总结+求最大转换序列
- 连续子列最大和问题
- 连续子数组的最大和问题
- apache的最大连续数问题
- 算法题:背包最大承重为20,算出装满水果后价格最高的组合,水果不能重复。
- 输入两个整数n和m,从数列1,2,3,……n中随意取几个数,使其和等于m。要求将所有的可能组合列出来。实际上就是一个背包问题
- 关于要求一串数字不超过某个数字可以达到的最大和(DP背包问题)
- 51nod 1062 序列中最大的数 (打表,连续区间问题)
- 最大连续和问题
- 动态规划-背包问题(状态转换)