各人(name)の拘束日時(date, begin, end) について以下のような予定表がある(3人以上でもよい)。
name date begin end
1 新井 2015/04/27 08:30 17:00
2 新井 2015/04/28 09:00 16:30
3 新井 2015/04/29 08:00 17:00
4 新井 2015/04/30 09:00 16:30
5 新井 2015/04/30 17:00 21:00
6 新井 2015/05/01 08:00 16:30
7 新井 2015/05/01 18:00 21:00
8 新井 2015/05/02 08:30 16:30
9 新井 2015/05/04 08:00 17:30
10 新井 2015/05/05 11:00 15:30
11 古田 2015/04/27 09:30 16:00
12 古田 2015/04/27 19:30 22:00
13 古田 2015/04/28 08:30 17:00
14 古田 2015/04/28 17:30 19:30
15 古田 2015/04/29 18:00 22:00
16 古田 2015/04/30 10:00 17:00
17 古田 2015/05/01 17:00 20:00
18 古田 2015/05/02 18:00 19:30
19 古田 2015/05/03 08:00 17:30
20 古田 2015/05/04 14:00 19:30
21 古田 2015/05/05 08:30 18:00
リストされている人全員が自由な時間が,連続する 3 時間以上となる,直近の日時を調べよ。ただし,6:00~22:00 の範囲であること。
func = function(s) {
# 6:00 ~ 22:00 までを 30 分を 1 コマとして何コマ目かを数字で表す
# 6:00~6:30 ==> 1, 6:30~7:00 ==> 2, ... , 21:30~22:00 ==> 32
hm = as.integer(unlist(strsplit(s, ":")))
hm[1] * 2 + (hm[2] == 30) - 11
}
inv = function(i) {
# 上記 func の逆関数コマ数を表す数字から,コマの開始時間を求める
sprintf("%02i:%02i", (i-1)%/%2+6, (i-1)%%2*30)
}
d = data.frame(stringsAsFactors = FALSE, # スケジュール表(文字列で)
name = c("新井", "新井", "新井", "新井", "新井", "新井", "新井",
"新井", "新井", "新井", "古田", "古田", "古田", "古田", "古田", "古田",
"古田", "古田", "古田", "古田", "古田"),
date = c("2015/04/27", "2015/04/28", "2015/04/29", "2015/04/30",
"2015/04/30", "2015/05/01", "2015/05/01", "2015/05/02",
"2015/05/04", "2015/05/05", "2015/04/27", "2015/04/27",
"2015/04/28", "2015/04/28", "2015/04/29", "2015/04/30",
"2015/05/01", "2015/05/02", "2015/05/03", "2015/05/04",
"2015/05/05"),
begin = c("08:30", "09:00", "08:00", "09:00", "17:00", "08:00",
"18:00", "08:30", "08:00", "11:00", "09:30", "19:30", "08:30",
"17:30", "18:00", "10:00", "17:00", "18:00", "08:00", "14:00",
"08:30"),
end = c("17:00", "16:30", "17:00", "16:30", "21:00", "16:30",
"21:00", "16:30", "17:30", "15:30", "16:00", "22:00", "17:00",
"19:30", "22:00", "17:00", "20:00", "19:30", "17:30", "19:30",
"18:00"))
d = d[order(d[, 2]), ] # 月日で並べ替え
n = nrow(d) # スケジュールの総数(行数)
t.begin = sapply(d[, 3], func) # 拘束開始時間をコマ数に変換
t.end = sapply(d[, 4], func) - 1 # 拘束終了時間をコマ数に変換
begin = 1 # 1 日分がどこからどこまでか
day = d[begin, 2]
for (i in 1:(n - 1)) {
if (d[i, 2] != d[i + 1, 2]) {
begin = c(begin, i + 1)
}
}
end = c(begin[-1] - 1, n)
for (i in seq_along(begin)) { # 日付ごとにチェック
time.table = integer(32) # コマ
for (j in begin[i]:end[i]) { # 拘束コマを 1 で埋める
time.table[t.begin[j]:t.end[j]] = 1
}
k = 1 # 連続する自由なコマ数を求める
while (k < 32) {
while (time.table[k] == 1) {
k = k + 1
if (k > 32) break
}
ks = k
if (k > 32) break
while (time.table[k] == 0) {
k = k + 1
if (k > 32) break
}
free.time = (k - ks) / 2 # コマ数を時間に直す(2 コマで 1 時間)
if (free.time >= 3) { # 自由時間が 3 時間以上なら結果出力
cat(sprintf("%s の %s ~ %s の %.1f 時間\n", d[j, 2], inv(ks), inv(k), free.time))
break
}
}
if (free.time >= 3) break
}
実行結果
2015/04/30 の 06:00 ~ 09:00 の 3.0 時間