Problem:
泥棒

宝物がたくさん収蔵されている博物館に、泥棒が大きな風呂敷を一つだけ持って忍び込みました。盗み出したいものはたくさんありますが、風呂敷が耐えられる重さが限られており、これを超えると風呂敷が破れてしまいます。そこで泥棒は、用意した風呂敷を破らず且つ最も価値が高くなるようなお宝の組み合わせを考えなくてはなりません。

風呂敷が耐えられる重さ W、および博物館にある個々のお宝の価値と重さを読み込んで、重さの総和が W を超えない範囲で価値の総和が最大になるときの、お宝の価値総和と重さの総和を出力するプログラムを作成してください。ただし、価値の総和が最大になる組み合わせが複数あるときは、重さの総和が小さいものを出力することとします。

Input

複数のデータセットが与えられます。各データセットは以下のような形式で与えられます。

W
N
v1,w1
v2,w2
:
vN,wN

１行目に風呂敷の耐えられる重さを表す整数 W (W ≤ 1,000)、２行目にお宝の数 N (1 ≤ N ≤ 1,000) が与えられます。続く N 行に i 番目のお宝の価値を表す整数 vi (0 ≤ vi ≤ 10,000) とその重さを表す整数 wi (0 ≤ wi ≤ W) の組がそれぞれ１行に与えられます。

W が 0 のとき入力の最後とします。データセットの数は 50 を超えません。

Output

各データセットに対して以下のように出力して下さい。

Case データセットの番号:
風呂敷に入れたお宝の価値総和
そのときのお宝の重さの総和

Sample Input

50
5
60,10
100,20
120,30
210,45
10,4
50
5
60,10
100,20
120,30
210,45
10,4
0

Output for the Sample Input

Case 1:
220
49
Case 2:
220
49

Solution in JAVA (judge verdict: Accepted)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

public class Main {
	static final int MAX_BAG_WEIGHT = 1000;
	static final int MAX_NUM_TREASURES = 1000;
	static final int MAX_VALUE = 10000;
	static final int WEIGHT = 0;
	static final int VALUE = 1;

	public static void main(String[] args){
		try{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int bagWeight = 0;
		int num_treasures = 0;
		int caseNumber = 1;
		Treasure[] treasure;
		Thief thief = new Thief();
		while(true){
			//bagを生成
			bagWeight = Integer.parseInt(br.readLine());
			if(bagWeight == 0 /*|| bagWeight > MAX_BAG_WEIGHT*/) break;
			Bag bag = new Bag(bagWeight);
			
			thief.setBag(bag);
			
			//お宝リストを生成
			num_treasures = Integer.parseInt(br.readLine());
//			if(num_treasures < 1 || num_treasures > MAX_NUM_TREASURES) break;
			treasure = new Treasure[num_treasures];
			for(int i = 0; i < num_treasures; i++){
				String[] inputs = (br.readLine()).split(",");
				int treasureValue = Integer.parseInt(inputs[WEIGHT]);
				int treasureWeight = Integer.parseInt(inputs[VALUE]);
				treasure[i] = new Treasure(treasureWeight, treasureValue);
			}
			
			//動的計画法
			int[] maxValueOfEachWeight = thief.getMaxValue(treasure);
			
			//価値がもっとも高いときの、もっとも軽い重量を出力する
			System.out.println("Case " + caseNumber++ + ":");
			System.out.println(maxValueOfEachWeight[maxValueOfEachWeight.length - 1]);
			System.out.println(thief.getMinWeightWhenMaxValue(maxValueOfEachWeight));
		}
		br.close();
		}catch(IOException e){
			e.printStackTrace();
		}
	}
	static class Bag{
		private int maxWeight;
		public Bag(int maxWeight) {
			this.maxWeight = maxWeight;
		}
		public int getMaxWeight() {
			return this.maxWeight;
		}
	}

	static class Treasure{
		private int weight;
		private int value;
		public Treasure(int weight, int value) {
			this.weight = weight;
			this.value = value;
		}
		public int getValue() {
			return this.value;
		}
		public int getWeight() {
			return this.weight;
		}
	}

	static class Thief{
		private Bag bag;
		public void setBag(Bag bag) {
			this.bag = bag;
		}
		/*TODO ruby実装*/
		public int[] getMaxValue(Treasure[] treasure){
			int[] maxValue = new int[this.bag.getMaxWeight() + 1];	//各バッグ積載可能重量での最大valueを格納する
			//重量が0のとき、treasureはつめないためvalue = 0
			maxValue[0] = 0;			
			//バッグには何もつめられていないため、0で初期化
			Arrays.fill(maxValue, 0);	
			//各treasureについて、バッグ積載可能重量に空きがあり、
			//treasureを追加することでvalueが大きくなるなら追加していく
			for(int i = 0; i < treasure.length; i++){
				int treasureWeight = treasure[i].getWeight();
				int treasureValue = treasure[i].getValue();
				for(int weight = this.bag.getMaxWeight(); weight >= treasureWeight; weight--){
					if(maxValue[weight - treasureWeight] < 0){
						//treasureが詰められない場合は次のアイテムを検討する
						break;
					}
					int tmpValue = maxValue[weight - treasureWeight] + treasureValue;
					maxValue[weight] = Math.max(maxValue[weight], tmpValue);
				}
			}
			return maxValue;
		}
		/*TODO ruby実装*/
		public int getMinWeightWhenMaxValue(int[] maxValueOfEachWeight){
			int minWeight = this.bag.getMaxWeight();
			int maxValue = maxValueOfEachWeight[minWeight];
			for(int weight = this.bag.getMaxWeight(); weight >= 0; weight--){
				if(maxValue > maxValueOfEachWeight[weight]){
					break;
				}
				minWeight = weight;
			}
			return minWeight;
		}
	}
}