問題文
https://www.hackerrank.com/challenges/equal
女の子が次のルールでチョコをあげる。
1. 特定の一人を除いて他全員にチョコ1個あげる
2. 特定の一人を除いて他全員にチョコ2個あげる
3. 特定の一人を除いて他全員にチョコ5個あげる
全員同数のチョコを持つ為に上記のオペーレーションを何回繰り返すか?
解き方
解き方は自分で思いついていませんが、エレガントな解き方と思いますので、書きたくなりました。
気づくべきところ
1. 一人除いて他の人全員にチョコあげる行為は、その一人だけからチョコもらっている操作と同様。
2. 1のため問題は、0に向かって全ての同僚が同じになるまで操作する。
3. 全ての同僚が同じ数のチョコを持つためには、各同僚が持つべき目的の数を決める。
4. 3で決めた数と初期に持っていたチョコの差分0になるまで何回操作をすればいいかを求める。この値が答えとなる。
アルゴリズム
0. 全ての同僚のチョコの数を配列aとする。
1. 一番少ない数のチョコ持っている同僚みつける。そのチョコの数をminとする。
2. 各同僚が持つべき目的の数は、min, min - 1, min - 2, min - 3, min - 4 である。
3. 2で決めた数字で差分をとる。delta[i] = a[i] - (min - j); 0<= j <= 4.
4. delta[i] = 5 * x + 2 * y + 1 * z という式が成り立つ。最小のステップ数を求める → つまり(x + y + z)が最小になるように下記のようにする。
x = delta[i] / 5;
y = delta[i] % 5 / 2;
z = delta[i] % 5 % 2 / 1;
sum += x + y + z;
5. 2-4を繰り返し、sumの最小値が答えとなる。
6. 補足:2でどうしてmin - 5, min -6などの数を目的の数として選ばないのか?を説明します。
min - 5を目的の数に選んだとします。
その場合の差分は、 delta1[i] = a[i] - (min - 5);となるこのときのxは下記のようになる。
x = delta1[i] / 5 = a[i] / 5 - min / 5 + 5 / 5 この「5 / 5 = 1」はいつもプラス1になり、1ステップ多くなることを意味します。つまりやっても無駄になります。5より大きな数はこのようにステップが無駄に増えるだけになります。
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.StringTokenizer;
/**
* @author munkhbat
* hackerrank equal
*
*/
public class Solution
{
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static int solve(int min, int[] a) {
// my answer goes below.
int ans = Integer.MAX_VALUE;
for (int j = 0; j <= 4; j++) {
int tmpans = 0;
for (int p = 0; p < a.length; p++) {
int delta = a[p] - (min - j);
int x = delta / 5;
int y = (delta % 5) / 2;
int z = ((delta % 5) % 2) / 1;
tmpans += x + y + z;
}
ans = Math.min(tmpans, ans);
}
return ans;
}
public static void main(String[] args) throws IOException {
int t = Integer.parseInt(br.readLine());
for (int i = 0; i < t; i++) {
int n = Integer.parseInt(br.readLine());
int[] a = new int[n];
StringTokenizer st = new StringTokenizer(br.readLine());
int min = Integer.MAX_VALUE;
for (int j = 0; j < n; j++) {
a[j] = Integer.parseInt(st.nextToken());
min = Math.min(min, a[j]);
}
pw.println(solve(min, a));
}
br.close();
pw.flush();
pw.close();
}
}