130323 slide all
TRANSCRIPT
2013/03/23合同練習会解説
問題作成、選択:松永 解説、テスター:池谷
問題 アルゴリズム 難易度(国内予選)
A 実装 A
B 実装 A
C シミュレーション A(Small) / B(Large)
D 幾何、場合分け B
E シミュレーション B
F 幾何、シミュレーション、貪欲 C-‐
G 横型探索(BFS) C-‐
H 動的計画法(DP) C-‐
I バックトラック(DFS) C-‐
J バックトラック/ビットDP C-‐ / C
K 構文解析、再帰 C
L バックトラック C+
総評
総評その2l 第1回ではやさしい幾何がなかったので、第2回では、入れるようにしたそうです l チームに1人くらい、できる人がいると頼もしいですね
l G~Lまでは典型問題なので、わからなかったら復習するといいでしょう l 復習しないと問題が解けないままだと思います
A 温度測定
原案: TopCoder SRM 310 Div 2 Easy
問題概要
l 1分間に1度、気温を測定する装置 l 不正確な測定値が存在する
l 値が-‐273度未満 l 前後2分以内に計測したすべての値との差が2より大きい
l 正しい測定値のみの平均気温を求める l すべて不適切な測定値ならば-‐300.0を出力
解法
1. i分のときに計測した気温が、適切か不適切かを判断する
l Boolean型の配列を用意して、i分のときの計測が正しいかどうかを求める
2. 適切な計測値だけで平均を求める l 正しい計測値だけの合計とその個数を求める l 型変換と0で割ることに注意する
ジャッジ解と提出状況
l ジャッジ解 l 松永(Java)50行 l 池谷(Java)51行
l 提出した数:14 l ACしたチーム数:9 l First AC時間:18min
B 成績調査
原案: Codeforces 152Aを改題
問題概要
l N人の学生の、m科目の成績がある l ある科目において、一番高い成績を取った人は「ベストな学生」である
l 1つでもベストである科目がある学生の人数を求める
解法
1. i番目の学生がベストであるのかどうかを計算する
1. まずは2次元配列に入力値を格納 2. 各列(縦)に対して、max値を求める 3. Max値と同じ値を持つならば、booleanの配列にtrueを格納する
2. 最終的にその数を数える
ジャッジ解と提出状況
l ジャッジ解 l 松永(C++)32行(マクロ部分含めず) l 池谷(Java)38行
l 提出した数:16 l ACしたチーム数:13 l First AC時間:4min
C センサー付きロボット
原案:オリジナル
問題概要
l 2次元平面上に置かれたロボット l F(直進), R(右), L(左)の命令 l 壁があると180度回転する l ロボットの最後の位置と、初期位置から最も離れた距離の位置を求める
l (Small):壁の数が4 l (Large):壁の数が4以上100以下
考察
l ロボットが距離1しか進まないことと、壁がx軸とy軸に平行であることから、壁にちょうどぶつかる
l つまり、ロボットが進んだ時に、壁の線分上に位置していれば壁にぶつかったと言える
l Largeを解くには、壁にぶつかる判定をどのように実装されるかが要求される
解法(Small, Large)l Small, Large共にシミュレーションしていけばよい l 現在のx, y, 方向、を値に持つ変数を用意 l 命令が来たら、移動or回転して、最も離れている位置であるならば、更新
l 最大距離判定の際に、無理に平方根を取る必要はないです l √を取らずに比較すれば誤差が怖くないです
Small解法l N = 4なので、長方形or正方形
l minX, minY, maxX, maxYを持っておけばよい
l 壁にぶつかる判定が楽 l x,y共に、最小値より大きく、最大値より小さければよい
l 逆に考えて、x,yが最小値または最大値であればfalse、としてもよい
Large解法l 入力値は0以上100以下なので、その座標が壁であるかどうかの配列を用意する l array[y座標][x座標] = 壁かどうか(true or false)
l それとは別に、壁の座標を記録しておき、進んだときに線上に存在するか、という方法でもできます
実装の工夫点とか
l (共通)方向ベクトルを作るといいです l int [] vx = {0,1,0,-‐1}; //上,右,下,左 l int [] vy = {1,0,-‐1,0}; l nextX = x + vx[dir] って感じで書きます
l C++だとpair<int, int>で座標管理できます
ジャッジ解と提出状況
l ジャッジ解 l (Small)松永(C++)64行 l (Small)池谷(Java)78行 l (Large)松永(C++)87行 l (Large)池谷(Java)90行
l 提出した数 5(small)/ 2(large) l ACしたチーム数:3 / 2 l First AC時間:98min / 99min
D 恋人同士の移動時間
原案: East Central North America 2011 I :Wally World
問題概要
l 平面上の点に2人の恋人がいる l 通過することができない壁が存在する
l 壁は線分でx,yのどちらかに平行
l 1秒間で1m進むことができる l 2人が合うのに必要な最小の時間を求める
サンプル解析
l サンプル1 l サンプル2
(5, 2) (7, 2)
1.00000000
(1, 2) (3, 2) (2, 1)
(2, 100)
1.41421356 = √2
考察と解法
l 2人の速さが同じなので、2人の最短距離の半分が求めたい時間になる l 出会う場所は、距離の半分の場所になる
l 壁がない時は2点の距離が最短距離になる l 2人の間に壁があるならば、壁の端を通るような経路を考えればよい l 壁の端点を通る経路は2通り l 2人の間に壁があるかどうか => 線分と線分の交差判定
線分と線分の交差判定
l ライブラリを公開している人を参考にしてください(割愛します)
l Javaならば、 Line2D.intersectsLine()というメソッドがあります
l ライブラリを持っていなくとも、2点から直線の式を求めて、壁の座標から判定することは可能です
l 易しい幾何が国内予選で出る可能性はゼロではないので、勉強しましょう
ジャッジ解と提出状況
l ジャッジ解 l 松永(C++)61行 l 池谷(Java)39行
l 提出した数:6 l ACしたチーム数:3 l First AC時間:87min
E 戦艦ゲーム
原案: GCPC 2012 A: Battleship
問題概要
l 2人のプレーヤーが交互に相手の戦艦を撃沈させていく
l 撃沈させた時、相手の戦艦が残っているならば、自分の順番を続けられる
l 2番目のプレーヤーは全滅してももう一回のターンができる
l ゲームの勝敗を求める
解法
l シミュレーションする l 事前に残り何体あるのか、を計算する l 当たっていれば、もう一回自分のターン、ただし残り個数が0ならターン交代
l 当たっていないならば、ターン交代 l 相手のターン終了時にどちらか一方でも戦艦の個数が0であれば終了する
l 最後に残り個数を判断して勝敗を計算する
実装の工夫点など
l 問題文をしっかりと理解しましょう l 重要な部分には線を引いたり、要約した紙を作るといいでしょう
l 3次元配列で図の状態を持つと楽かもです l Field[0: 自分, 1:相手][h][w]といった具合
l シミュレーション問題は、ある程度紙にまとめてから書いた方がいいと思います l コーディングしてから失敗に気づく、というのは、結構なロスだと思われます
ジャッジ解と提出状況
l ジャッジ解 l 松永(C++)78行 l 池谷(Java)79行
l 提出した数:13 l ACしたチーム数:3 l First AC時間:78min
F 頑固なヌーRick
原案: Asia Taiwan 2004
問題概要
l ヌーが牧草地に向かって移動を繰り返す l 距離D以内で移動しないといけない l FSの方向に最も近い方向の場所を選ぶ
l 最低限FSの方向に直角未満で進まないとダメ
l 方向を変える角度が直角以内でないとダメ
l ヌーが移動した経路を求める
解法
l 経路はただ一つに決まるので、素直にシミュレーションをしていけばよい
l 満たさないといけない条件 l 距離D以内 l FSの方向に90度以内 l 直前の方向と90度以内
l 最もFSの角度が小さいものを選べばよい l 角度の計算方法が分かればできる
角度の計算
l 内積の公式より、 l v1・v2=|v1||v2|cosθ から式変形して、 l θ=arccos(v1・v2 / (|v1||v2|))
l C++では、complex型のarg関数で角度計算できるようです
ジャッジ解と提出状況
l ジャッジ解 l 松永(C++)73行 l 池谷(Java)83行
l 提出した数:1 l ACしたチーム数:1 l First AC時間:198min
G エレベータの故障
原案: NCPC 2011 D Elevator Trouble
問題概要
l エレベーターに乗って、s階からg階に行く l エレベーターは、上にu階、または、下にd階移動できる
l ボタンを押す最小回数を求める l 無理ならば、”use the stairs”を出力する
解法
l 横型探索をします l 現在の位置と何回ボタンを押したのか、を状態として持って、状態をキューで管理する
l キューがなくなるまで、キューから状態を取得して、新たな状態をキューに入れるという操作を繰り返す
l 重複した状態は、キューに入れる必要なし
l コードを見た方がわかりやすいと思います
ジャッジ解と提出状況
l ジャッジ解 l 松永(C++)52行 l 池谷(Java)64行
l 提出した数:13 l ACしたチーム数:6 l First AC時間:56min
H 良い連立政権
原案: BAPC 2012 G: Good Coalision
問題概要
l n個の政党があり、政党ごとに、獲得した議席数と任期を満了できる確率が与えられる
l 政党を連立させ、過半数(=76以上)となるときの最大の任期満了率を求める l 連立させると、議席数は加算され、確率は掛け算となる
解法
l 動的計画法 l dp[i番目までの政党][議席数] = 確率 l 初期値はdp[0][0] = 100.0 l その政党を使うor使わないの2通りの遷移
l 使うなら議席数を加算して、確率を乗算 l 使わないなら議席数、確率はそのままで遷移
l 最終的に議席数が76以上のiにおける、dp[n][i]の最大値を求めればよい
ジャッジ解と提出状況
l ジャッジ解 l 松永(C++)42行 l 池谷(Java)39行
l 提出した数:4 l ACしたチーム数:3 l First AC時間:147min
I 彫像
原案: Codeforces #94 Div2 C: Statues
問題概要
l 8×8のチェス盤がある l 左下にいるMariaが右上に到達したい l Mariaの移動は8近傍。彫像のマスには不可 l 彫像はMariaが移動していると同時に1マス下に移動する。一番下のときは消える
l 現在Mariaのマスにいると彫像の勝ち l 右上に進んだらMariaの勝ち l 勝敗を求めよ
解法
l 右上にたどり着ければもちろん勝ち l また、8ターン生き延びれたらMariaの勝ちは必然となる l 彫像は長くても8ターンで消えてしまう l 実質は7ターン目でも大丈夫だと思われる
l つまり、バックトラックをして、右上にたどり着けるor深さ8の所までたどり着ければ勝ちとなる
ジャッジ解と提出状況
l ジャッジ解 l 松永(C++)84行 l 池谷(Java)76行
l 提出した数:6 l ACしたチーム数:1 l First AC時間:109min
J アレルギーテスト
原案: NCPC 2009 C Allergic Test
問題概要
l K個のアレルゲンが与えられる l アレルゲンはD日間活性している l 一日に最大1つアレルゲンを与えることができる
l ある日にちのときに、アレルゲンが2つ以上活性化していると検査できない
l テスト計画を実施する最短の日時を求める
サンプル解析
l k = 3, {2, 2, 2} l k = 5, {1,4,2,5,2}
答えは5
各アレルゲンごとに 最低一日は、単体のテストの 日にちを作らないといけない
答えは10
Small解法l バックトラックをして、並び順を全探索する
l 使ってないものを一つ選んで、使ってるものの右側に追加するようなイメージ
l 現在の深さ、次のテストは何日から始めればよいか、現在の合計を引数をして再帰していけばよいです
l 計算量はk! = 9! = 10^5くらい l LargeだとTLEとなってしまう
Large解法l bitDP[使った集合][重複してもよい日数]
l 使った集合に対して、重複してもよい日数がxのときの最小の日数を求めていく
l 初期状態は0、最終的な状態は(1 << k) -‐ 1 l いわゆる「渡す(飛ばす)DP」で書いた方がわかりやすいと思います
l 計算量はO(k * 8 * 2 ^ k) = 10^ 8くらい
ちょっと高度なお話
l 最小日数が同じ場合であれば、重複してもよい日数が多い方がよいです l 使った集合に対して、最小の日数と、最大の重複してもよい日数を持っているだけでよい
l 計算量はO(k * 2 ^ k) = 10^ 7
重複日数3 重複日数0
ジャッジ解と提出状況
l ジャッジ解 l (Small)池谷(Java)44行 l (Large)松永(C++)55行 l (Large)池谷(Java)58行
l 提出した数:2(small)/0(large) l ACしたチーム数:0/0 l First AC時間:-‐-‐/-‐-‐
K 等式
原案:オリジナル
問題概要
l x,y,zの3つの変数を含む式がある。 l 式は足し算と掛け算のみ l 右辺は整数
l 式が成立するような変数の組み合わせは何通りあるか求める
解法
l x,y,zについて1~100までループを回して、構文解析をする
l 掛け算が省略されているので、掛け算の記号を追加して構文解析するといいと思います
l 構文解析の入門的問題はAOJ0109です
ジャッジ解と提出状況
l ジャッジ解 l 松永(C++)124行 l 池谷(Java)141行
l 提出した数:3 l ACしたチーム数:3 l First AC時間:128min
L 平面上の蛇
原案: East Central North America 2006 G: Snakes on a Plane
問題概要
l n * mのグリッドがある l 蛇を構成する四角形は1を表す l 蛇は4方向で2つ、1の正方形と接している
l 蛇の頭としっぽは例外
l 最大蛇は、0の正方形を1に変換しても、蛇の長さが変わらない蛇のことである
l 最大蛇の数を求めよ
解法
l 最大蛇でない時の判定 l 蛇の頭またはしっぽのまわりに1を追加する l 追加したマスの周りに、1のマスが1個しかない時、長さが長くできる
l 1のマスの次数が3つ以上1のマスであるとき、蛇ではないので、それも除外する
l 最大蛇でないと確定できたら、違う色に塗りつぶすなどすればいいでしょう
ジャッジ解と提出状況
l ジャッジ解 l 松永(C++)134行 l 池谷(Java)93行
l 提出した数:5 l ACしたチーム数:0 l First AC時間:-‐-‐
お疲れさまでした