Problem:
Problem D: The Great Summer Contest

現在、人々の娯楽はプログラミングコンテストに限られている。彼女が所属しているとある中学校の娯楽部の活動内容は、プログラミングコンテストを企画し運営することだ。彼女の仕事は問題を作成することではない。多くの人から問題を募り、審判団を組織し、またコンテストの宣伝を行う、いわば裏方のお仕事だ。カリスマ作題者や著名なアルゴリズマーと違い、そういった仕事をする人に光が当たることはほとんどない。存在感はないけれども欠かすことのできないその仕事に、彼女は誇りを持って取り組んでいた。

娯楽部は常に問題を募集しているが、それらの問題は以下の 6 種類に分類される。

Math

Greedy

Geometry

DP

Graph

Other

幸いにも多くの問題が集まったので、彼女はたくさんコンテストを開こうと考えた。コンテストは 3 問の問題からなるが、彼女はコンテストがより教育的になるようにと、以下の 4 種類のコンテストを開くことに決めた。

数学ゲーコンテスト: Math の問題と DP の問題合わせて3問の問題セット

アルゴリズムゲーコンテスト: Greedy の問題と Graph の問題合わせて3問の問題セット

実装ゲーコンテスト: Geometry の問題と Other の問題合わせて3問の問題セット

バランスの良いコンテスト: Math または DP から 1 問、Greedy または Graph から 1 問、Geometry または Other から 1 問、合わせて3問の問題セット

もちろん、あるコンテストに出題した問題は他のコンテストに出題することはできない。彼女の望みは、できるだけ多くのコンテストを開くことだ。6 種類の問題のストック数は分かっているが、さて、最大何回コンテストを開けるだろうか。彼女にとってこれは難しい問題だが、カリスマアルゴリズマーであるあなたなら解決できるはずだ。

Input

入力は複数のケースからなる。
各ケースは以下のフォーマットで与えられる。

nMath nGreedy nGeometry nDP nGraph nOther

各入力の値はそれぞれの種類の問題のストックの数を表す。

入力の終わりは

0 0 0 0 0 0

からなる行によって与えられる。

各値は以下の条件を満たす。

nMath + nGreedy + nGeometry + nDP + nGraph + nOther ≤ 100,000,000

またテストケースの数は20,000個を超えない。

Output

開催可能なコンテストの最大数を1行に出力せよ。

Sample input

1 1 1 1 1 1
1 1 1 0 0 0
1 0 0 0 1 1
3 0 0 3 0 0
3 1 0 1 3 1
1 2 0 2 0 1
0 0 1 1 0 3
1 0 0 1 1 0
0 0 0 0 0 0

Sample output

2
1
1
2
3
1
1
0

The University of Aizu Programming Contest 2011 Summer

原案: Tomoya Sakai

問題文: Takashi Tayama

Solution in JAVA (judge verdict: Wrong Answer)

import java.util.*;

class Main{

    void solve(){
        Scanner sc = new Scanner(System.in);

        while(true){
            int[] set = new int[3];
            set[0] = sc.nextInt();
            set[1] = sc.nextInt();
            set[2] = sc.nextInt();
            set[0] += sc.nextInt();
            set[1] += sc.nextInt();
            set[2] += sc.nextInt();

            if(set[0]==0 && set[1]==0 && set[2]==0) break;

            int num = set[0]/3+set[1]/3+set[2]/3;
            num += Math.min(set[0]%3, Math.min(set[1]%3, set[2]%3));

            int max = num;
            for(int i=0; i<1<<3; i++){
                int num2 = 0;
                int min = Integer.MAX_VALUE;
                for(int j=0; j<3; j++){
                    if(set[j]-1>=0 && (1<<j & 1)==0){
                        num2 += (set[j]-1)/3;
                        min = Math.min(min, set[j] - (set[j]-1)/3*3);
                    }else{
                        num2 += set[j]/3;
                        min = Math.min(min, set[j]%3);
                    }
                }
                max = Math.max(max, num2+min);

                int num3 = 0;
                int min2 = Integer.MAX_VALUE;
                for(int j=0; j<3; j++){
                    if(set[j]-2>=0 && (1<<j & 1)==0){
                        num3 += (set[j]-2)/3;
                        min2 = Math.min(min2, set[j] - (set[j]-2)/3*3);
                    }else{
                        num3 += set[j]/3;
                        min2 = Math.min(min2, set[j]%3);
                    }
                }
                max = Math.max(max, num3+min2);
            }

            System.out.println(max);
        }
    }

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