トーナメントの勝ち点から導け!

photo by oskay
正答率95%なので簡単かと思ったら、意外と難しかった。でも考え方が分かると、実装するまで時間はかからない。ひらめきが必要な問題なのかな。
TopCoder Statistics - Problem Statement
問題:各チーム一対一で対戦します。勝利すると2点、負けると0点、引き分けでは二チームにそれぞれ1点ずつ入ります。どのチームと何回するかという制限はありません。(一度も戦わないチームもあります。)
各チームのゲーム終了時の勝ち点の合計が配列として二与えられたとき、そこから最小の対戦回数を返しなさい。
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <numeric>
#include <algorithm>
using namespace std;
class TheTounamentDivTwo{
public:
int find(vector <int> A){
int answer=0;
vector <int> B;
printf("\n");
for(int i=0;i<A.size();i++){
B.push_back(A[i]%2);
answer+=A[i]/2;
printf("%d ",B[i]);
}
int sum=accumulate(B.begin(),B.end(),0);
printf("\n a=%d:sum=%d:return=%d\n",answer,sum,sum/2+answer);
printf((sum%2==0)? "ok\n":"no\n");
return ((sum%2==0)? (sum/2+answer):-1);
}
};
int main(){
TheTounamentDivTwo ob1;
int a[]={2, 3, 7, 20};
vector <int> b(a,a+4);
for(int j=0;j<b.size();j++){
printf("%d ",b[j]);
}
ob1.find(b);
return 0;
}
- まず、各チームの勝ち点を2で割ります。この商がそのチームが勝った試合の回数です。
- そしてそのあまりを配列Bに入れます。
- 商の合計を総試合数に足します。
- 余りの配列は0か1の要素をもつ配列です。引き分けの場合は各チームに1点ずつ入るので、要素1をもつチームが偶数個ないといけません。
- 偶数個ない場合は-1を返し、あるときは総試合数に配列B合計/2を足します。
- sumはaccumulateを用います。numericをinclude。