Problem:
ばらばら饅頭

会津若松市にある和菓子屋・友栗堂の店長さんは、とても腕のいい職人さんなのにちょっと気分屋なのが玉にキズです。店長さんの作る饅頭はとても美味しいのですが、その時の気分によって大きさがまちまちになってしまいます。

見かねた店長さんの奥さんは、大きさと重さがばらばらな饅頭を袋に詰めて売り出すことを思いつきました。一定の重さになるように饅頭を袋に詰めて売れば、一つ一つの大きさはばらばらでも一定の値段で売り出すことが出来ますし、どんな饅頭が入っているのか開けるまでわからないというサプライズも売りになるかもしれません。
「ばらばら饅頭」という名前で売りだしたところ、新しいアイディアが話題となり友栗堂はたちまち評判となりました。しかし、問題もあり、袋に入れる饅頭の組み合わせ方によって作れる「ばらばら饅頭」の数が変わり、無駄が発生してしまうことがありました。アルバイトで友栗堂に来ていたあなたは無駄なく袋に詰めるためにプログラムをつくることにしました。

饅頭の重さは1から9の9種類あります。袋に詰める時には、饅頭の重さの合計がぴったり10になるように詰め込みます。饅頭の組み合わせ方は1+1+2+4+2=10や1+1+1+1+1+5=10などで、同じ重さの饅頭をいくつ使っても構いません。

作られる饅頭の個数と饅頭の重さの情報を入力とし、作ることのできる「ばらばら饅頭」の最大の数を出力するプログラムを作成してください。

入力

複数のデータセットが与えられます。入力の終わりはゼロひとつで示されます。各データセットは以下の形式で与えられます。

n
m1 m2 ... mn

1行目に饅頭の個数 n (2 ≤ n ≤ 100) が与えられます。
2行目に各饅頭の重さmi (1 ≤ mi ≤ 9) が与えられます。

データセットの数は 100 を超えません。

出力

データセットごとに、詰め込むことのできた「ばらばら饅頭」の最大の数を1行に出力します。

入力例

5
4 9 1 3 8
10
8 5 3 6 2 1 4 5 4 5
9
5 7 3 8 2 9 6 4 1
0

出力例

1
4
4

Solution in JAVA (judge verdict: Time Limit Exceeded)

import static java.util.Arrays.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.List;
import java.util.StringTokenizer;

public class Main {

	static void tr(Object... os) {
		System.err.println(deepToString(os));
	}

	void solve() {
	for (;;) {
		int n = sc.nextInt();
		if (n == 0) return;
		int[] a = sc.nextIntArray(n);
		int[] b = new int[10];
		for (int x : a) b[x]++;
		int res = b[5] / 2;
		b[5] %= 2;
		for (int i = 1; i <= 4; i++) {
			int m = Math.min(b[i], b[10 - i]);
			b[i] -= m;
			b[10 - i] -= m;
			res += m;
		}
		patternList = new java.util.ArrayList<int[][]>();
		make(b);
		md = 0;
		search(b, 0, 0);
		System.out.println(res + md);
	}
	}
	int md;
	void search(int[] b, int d, int s) {
		if (d >= md) {
			md = d;
		}
		for (int i = s; i < patternList.size(); i++) {
			int[][] p = patternList.get(i);
			boolean ok = true;
			for (int[] k : p) {
				b[k[0]] -= k[1];
				if (b[k[0]] < 0) ok = false;
			}
			if (ok) {
				search(b, d + 1, i);
			}
			for (int[] k : p) {
				b[k[0]] += k[1];
			}
		}
	}

	List<int[][]> patternList;
	void make(int[] b) {
		int[] pattern = new int[10];
		dfs(b, pattern, 0, 0);
	}

	void dfs(int[] b, int[] pattern, int depth, int sum) {
		if (sum == 10) {
			if (depth > 2) {
				int[] hist = new int[10];
				for (int i = 0; i < depth; i++) {
					hist[pattern[i]]++;
				}
				int nz = 0;
				for (int i = 0; i < hist.length; i++) if (hist[i] > 0) nz++;
				int[][] k = new int[nz][2];
				int p = 0;
				for (int i = 0; i < hist.length; i++) if (hist[i] > 0) {
					k[p][0] = i;
					k[p][1] = hist[i];
					p++;
				}
				patternList.add(k);
			}
			return;
		}
		int s = (depth == 0) ? 1 : pattern[depth-1];

		for (int i = s; i <= 9; i++) if (b[i] > 0 && sum + i <= 10) {
			pattern[depth] = i;
			dfs(b, pattern, depth + 1, sum + i);
			pattern[depth] = 0;
		}
	}

	public static void main(String[] args) throws Exception {
		new Main().run();
	}

	MyScanner sc = null;
	PrintWriter out = null;
	public void run() throws Exception {
		sc = new MyScanner(System.in);
		out = new PrintWriter(System.out);
		for (;sc.hasNext();) {
			solve();
			out.flush();
		}
		out.close();
	}

	class MyScanner {
		String line;
		BufferedReader reader;
		StringTokenizer tokenizer;

		public MyScanner(InputStream stream) {
			reader = new BufferedReader(new InputStreamReader(stream));
			tokenizer = null;
		}
		public void eat() {
			while (tokenizer == null || !tokenizer.hasMoreTokens()) {
				try {
					line = reader.readLine();
					if (line == null) {
						tokenizer = null;
						return;
					}
					tokenizer = new StringTokenizer(line);
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
		}
		public String next() {
			eat();
			return tokenizer.nextToken();
		}
		public String nextLine() {
			try {
				return reader.readLine();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
		public boolean hasNext() {
			eat();
			return (tokenizer != null && tokenizer.hasMoreElements());
		}
		public int nextInt() {
			return Integer.parseInt(next());
		}
		public long nextLong() {
			return Long.parseLong(next());
		}
		public double nextDouble() {
			return Double.parseDouble(next());
		}
		public int[] nextIntArray(int n) {
			int[] a = new int[n];
			for (int i = 0; i < n; i++) a[i] = nextInt();
			return a;
		}
	}
}