Go: package main

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"strconv"
	"strings"
)

const MaxW = 1000
const MaxN = 1000

type Tuple struct {
	Value  int
	Weight int
}

func nextLine(sc *bufio.Scanner) string {
	sc.Scan()
	return sc.Text()
}

func solve(w int, n int, vws []Tuple) Tuple {
	var dp [MaxN + 1][MaxW + 1]int

	for i := 0; i < n; i++ {
		for j:= w; j > 0; j-- {
			if j < vws[i].Weight {
				dp[i + 1][j] = dp[i][j]
			} else {
				dp[i + 1][j] = int(math.Max(float64(dp[i][j]), float64(dp[i][j - vws[i].Weight] + vws[i].Value)))
			}
		}
	}

	maxValue := dp[n][w]
	minWeight := w

	for j := w - 1; j > 0; j-- {
		if maxValue == dp[n][j] {
			minWeight = j
		} else {
			break
		}
	}

	return Tuple{Value: maxValue, Weight: minWeight}
}

func main() {
	var sc = bufio.NewScanner(os.Stdin)
	index := 1
	for {
		var w, n int
		w, _ = strconv.Atoi(nextLine(sc))
		if w == 0 {
			return
		}
		n, _ = strconv.Atoi(nextLine(sc))

		vws := make([]Tuple, n, n)
		for i := 0; i < n; i++ {
			array := strings.Split(nextLine(sc), ",")
			v, _ := strconv.Atoi(array[0])
			w, _ := strconv.Atoi(array[1])
			vws[i] = Tuple{Value: v, Weight: w}
		}

		t := solve(w, n, vws)
		fmt.Printf("Case %d:\n", index)
		fmt.Println(t.Value)
		fmt.Println(t.Weight)
		index++
	}
}

C++: #include <cstdio>
#include <algorithm>

using namespace std;

int dp[1000][1001],t[1000],w[1000];

int main(){
  for(int c=1;;c++){
    int n,q,i,j;
    scanf("%d",&q); if(q==0) break;
    scanf("%d",&n);

    for(i=0; i<n; i++)
      scanf("%d,%d",&t[i],&w[i]);

    for(i=0; i<=q; i++)
      dp[0][i] = (w[0]<=i)?t[0]:0;

    for(i=1; i<n; i++)
      for(j=0; j<=q; j++){
	if(j+w[i]<=q)
	  dp[i][j+w[i]] = dp[i-1][j]+t[i];
	dp[i][j] = max(dp[i][j],dp[i-1][j]);
      }

    int mw=0,mt=0;
    for(j=0; j<=q; j++)
      if(dp[n-1][j]>mt){
	mt = dp[n-1][j];
	mw = j;
      }

    printf("Case %d:\n%d\n%d\n",c,mt,mw);
  }
}

C++: #include <bits/stdc++.h>
using namespace std;

struct Item{
	int v,w;
	int idx;	
};



const int INF = 1000000000;
class Knapsack{
public:
	struct DPInfo{
		int weight,trueValue;
		bool operator < (const DPInfo &op) const {
			return weight != op.weight ? weight < op.weight : trueValue > op.trueValue; // INVERSE!!
		}
	};

	int maximumWeight;
	vector<Item> items;
	Knapsack(int maximumWeight_,vector<Item> items_) : maximumWeight(maximumWeight_),items(items_) {
		used.resize(items.size(),false);
		totalWeight = totalValue = 0;
		sort(items.begin(),items.end(),[](Item a,Item b){ return a.v * b.w > b.v * a.w; });
	}
	int totalValue;
	int totalWeight;
	vector<bool> used;
	bool operator < (const Knapsack &op) const {
		if( totalValue == op.totalValue )
			return totalWeight > op.totalWeight;
		return totalValue < op.totalValue;
	}
	//??¢??????????????\?????¨??????????????§????????????????????????
	pair<Knapsack,Knapsack> devideItems(int valueThreshold) const{
		Knapsack low = *this, high = *this;
		low.items.clear();
		high.items.clear();
		for(int i = 0 ; i < items.size() ; i++){
			if( items[i].v <= valueThreshold){
				low.items.push_back(items[i]);
			}else{
				high.items.push_back(items[i]);
			}
		}
		return {low,high};
	}

	vector<DPInfo> makeDPtable(int itemscale) const{
		if( items.size() == 0 ){
			return vector<DPInfo>(1,{0,0});
		}
		Knapsack compressed = *this;
		int maximumValue = -INF;
		for( auto i : compressed.items ){
			maximumValue = max(maximumValue,i.v);
		}
		double rate = min(1.0,1.*itemscale/maximumValue);
		for( auto &i : compressed.items ){
			i.v = (int)(ceil(rate*i.v)+1e-9);
		}

		int scale = 0;
		for( auto &i : compressed.items ){
			scale += i.v;
		}
		vector<DPInfo> dp(scale+1,{INF,-INF});
		dp[0] = {0,0};
		int sum = 0;
		for(int i = 0 ; i < compressed.items.size() ; i++){
			if( compressed.used[i] ) continue;
			sum += compressed.items[i].v;
			for(int j = sum ; j >= compressed.items[i].v ; j--){
				DPInfo nextV;
				nextV.weight = dp[j-compressed.items[i].v].weight + compressed.items[i].w;
				nextV.trueValue = dp[j-compressed.items[i].v].trueValue + items[i].v;
				if( nextV < dp[j] ){
					dp[j].weight = nextV.weight;
					dp[j].trueValue = nextV.trueValue;
				}
			}
		}
		return dp;
	}

	int BigSmallDP(int valueThreshold) const{
		auto tmp = devideItems(valueThreshold);
		auto dp1 = tmp.first.makeDPtable(valueThreshold);
		auto dp2 = tmp.second.makeDPtable(valueThreshold);
		auto prepare = [](const vector<DPInfo> &dp){
			vector< pair<int,int> > tmp;
			vector< pair<int,int> > res;
			for(int i = 0 ; i < dp.size() ; i++){
				if( dp[i].weight == INF ) continue;
				pair<int,int> key = {dp[i].weight,dp[i].trueValue};
				tmp.push_back(key);
			}
			sort(tmp.begin(),tmp.end(),[](pair<int,int> a,pair<int,int> b){
				return make_pair(a.second,a.first) < make_pair(b.second,b.first);
			});
			for( auto key : tmp ){
				while( res.size() && res.back().first >= key.first ) res.pop_back();
				res.push_back(key);
			}
			return res;
		};
		vector< pair<int,int> > happySeq1 = prepare(dp1);
		vector< pair<int,int> > happySeq2 = prepare(dp2);
		
		int limit = maximumWeight - totalWeight;
		int j = happySeq2.size() - 1;
		pair<int,pair<int,int>> maximumPair = {-1,{-1,-1}};

		for(int i = 0 ; i < happySeq1.size() ; i++){
			while( j &&happySeq2[j].first > limit - happySeq1[i].first ) j--;
			if( happySeq2[j].first + happySeq1[i].first <=  limit) 
				maximumPair = max(maximumPair,{happySeq1[i].second+happySeq2[j].second,{happySeq1[i].first,happySeq2[j].first}});
		}
		cout << maximumPair.first << endl;
		cout <<  maximumPair.second.first + maximumPair.second.second << endl;
		
		return maximumPair.first;
	}
	
	// int iterativeKnapsack(int step){
		// int threshold = 10;
		// int cur = -1;
		// while(1){
			// threshold += step;
			// int nex = BigSmallDP(threshold);
			// if( cur == nex ){
				// cerr << threshold << endl;
				// return cur;
			// }
			// else cur = nex;
		// }
	// }
};



pair<int,vector<Item>> makeTestcase(int size){
	vector<Item> res;
	for(int i = 0 ; i < size ; i++){
		res.push_back({rand()%10000+1,rand()%10000+1,i});
	}
	int n = rand() % 10000 * size;
	return {n,res};
}



int main(){
	int w;
	
	int t = 1;
	while( cin >> w && w ){
		int n;
		vector<Item> items;
		cin >> n;
		for(int i = 0 ; i < n ; i++){
			int x,y;
			scanf("%d,%d",&x,&y);
			items.push_back({x,y,i});
		}
		cout << "Case "<< t++ << ":"<<endl;
		Knapsack(w,items).BigSmallDP(200);
		
	}
	// int trying = 2000;
	// int all = 0;
	// int suc = 0;
	// for(int i = 0 ; i < trying ; i++){
		// int n;
		// vector<Item> items;
		// tie(n,items) = makeTestcase(100);
		// Knapsack knap(n,items);
		// auto uso = knap.BigSmallDP(1000);
		// auto tru = knap.BigSmallDP(2000);

		// if( tru != uso ){
			// cerr << tru << " " << uso << " " << i << endl;
		// }else{
			// cerr << suc << endl;
			// suc++;
		// }
		// all++;
	// }
	// cerr << suc << "/" << all << endl;
}

C++: #include <iostream>
#include <vector>

using namespace std;

int main() {
    int W, N, v, w;
    char c;
    int case_ = 0;

    while (cin >> W) {
        if (W == 0) break;
        cin >> N;
        case_++;

        int dp[N + 1][W + 1];
        fill(dp[0], dp[N + 1], 0);
        dp[0][0] = 0;

        for (int i = 0; i < N; i++) {
            cin >> v >> c >> w;
            for (int j = 0; j <= W; j++) {
                if (j < w) {
                    dp[i + 1][j] = dp[i][j];
                } else {
                    dp[i + 1][j] = max(dp[i][j], dp[i][j - w] + v);
                }
            }
        }

        int max_v = dp[N][W];
        int min_w;

        for (int i = W; i >= 0; i--) {
            if (dp[N][i] == max_v) min_w = i;
            else break;
        }

        cout << "Case " << case_ << ":" << endl;
        cout << max_v << endl;
        cout << min_w << endl;
    }
}