Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Upcoming SlideShare
各種問題の解説
各種問題の解説
Loading in …3
×
1 of 87

WUPC2012

3

Share

Download to read offline

早稲田大学プログラミングコンテスト(WUPC)2012の問題解説

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

WUPC2012

  1. 1. WUPC2012 問題解説
  2. 2. 全体を通して ¤  難易易度度 ¤  簡単すぎor難しすぎるのではと⼼心配してました ¤  ICPC国内予選より少し簡単な程度度 ¤  出題ジャンル ¤  アルゴリズムの特定の知識識を要する問題は出したくなかった ¤  最⼤大流流とか、データ構造とか ¤  逆に⾔言えば、知識識だけでは解けない問題にしたつもりです
  3. 3. 想定難易易度度 # 問題名 ジャンル 難易易度度 SRM div2 A 招待状 ループ、場合分け ☆ 250 B パスワード ひらめき、⽂文字列列 ☆ 300 C ⾃自宅宅からの脱出 探索索 ☆☆ 400 D 三⾓角パズル 動的計画法 ☆☆☆ 500 E 会場への道 グラフ ☆☆☆☆ 700 F 最後の問題 累累積和 ☆☆☆☆☆ 1000
  4. 4. Problem A  招待状 ⽇日付の計算、場合分け、ループ
  5. 5. 問題 ¤  区間内の⽇日数を答える問題 ¤  ma⽉月da⽇日 〜~ mb⽉月db⽇日 ¤  3/1 〜~ 3/10 なら 9⽇日 ¤  2/1 〜~ 3/1 なら  29⽇日 ¤  どうやって数えるか?
  6. 6. ⽅方針 ¤  場合分け ¤  ⽉月が同じだった場合 ¤  ⽇日付の差がそのまま答えになる ¤  ⽉月が違う場合 ¤  (ma⽉月da⽇日 〜~ ma⽉月(その⽉月の最⼤大⽇日数)⽇日)    + (X⽉月の最⼤大⽇日数 : ma < X < mb)     + (mb⽉月1⽇日 〜~ mb⽉月db⽇日)    が答え
  7. 7. 実装例例(説明のための擬似⾔言語です) // ⽉月ごとの最⼤大の⽇日数 int[] max = {0, 31, 29, 31, 30, 31, 30 31, 31, 30, 31, 30, 31}; if (ma == mb) { return db – da; } else { int ans = (max[ma] - da) + (db - 1); for (int m = ma + 1 ; m <= mb – 1 ; m++) { ans += max[m]; } return ans; }
  8. 8. Problem B  パスワード ⽂文字列列、ひらめき、辞書順ソート、⼒力力任せ法
  9. 9. 問題 ¤  ⽂文字列列が複数与えられるので、それらを2つ以上くっつけたも のの中で辞書順最⼩小なものを求めたい ¤  例例 : “abc”, “def”, “ghi” ¤  “abcdef”, “abcghi”, “defabc”, “defghi”, “ghiabc”, “ghidef”, “abcdefghi”, “abcghidef”, “defabcghi”, “defghiabc”, “ghiabcdef”, “ghidefabc” ¤  => “abcdef” が上記の中で辞書順最⼩小
  10. 10. ⽅方針の前に ¤  気付いてほしいこと ¤  結合する⽂文字列列は「2つ以上」とあるが、考えるのは2つの⽂文字列列 を結合する場合だけでいい ¤  ⽂文字列列 A に⽂文字列列 B を⾜足してできた⽂文字列列 A + B ¤  必ず A < A + B (辞書順⽐比較の定義より) ¤  2つの⽂文字列列を結合した⽂文字列列の中で辞書順最⼩小なものを A と おく。A に何を⾜足しても辞書順最⼩小にはならない
  11. 11. ⽅方針 ¤  2つの⽂文字列列の順列列をすべて試す ¤  はじめにダミー⽂文字列列 (“~”, “zzz……zz”) などを辞書順最⼩小とし ておき、より辞書順で⼩小さいものが⾒見見つかったら⼊入れ替えていく ¤  必要な計算量量を⾒見見積もろう ¤  ⽂文字列列2つの組み合わせを調べる ¤  ⽂文字列列数 N の⼆二乗に⽐比例例した時間が必要。 ¤  辞書順⽐比較 ¤  ⽂文字列列の⻑⾧長さ L に⽐比例例した時間が必要。 ¤  全体で O(N2L) のアルゴリズム
  12. 12. ⽅方針 ¤  O(N2L) のアルゴリズム ¤  Nの最⼤大値 : 50 ¤  Lの最⼤大値 : 50 + 50 = 100 ¤  max(N2L) = 50 * 50 * 100 = 250,000 ¤  普通のコンテストだったら⼗十分実⾏行行制限時間内に間に合う。 ¤  ⽬目安[1] : 制限時間が1秒の場合 ¤  1,000,000 : 余裕を持って間に合う。 ¤  10,000,000 : おそらく間に合う。 ¤  100,000,000 : ⾮非常にシンプルな処理理でない限り厳しい。 [1] 秋葉葉拓拓哉,岩⽥田陽⼀一,北北川宜稔,プログラミングコンテストチャレンジブック,p20,2010
  13. 13. 別の⽅方針? ¤  与えられた⽂文字列列を辞書順でソートし、最初の⼆二つをつなげ たものが答えなのでは? ¤  より辞書順で早いものは前に来て欲しいので ¤  実は違う。⽂文字列列の⻑⾧長さが違うのでうまくいかない! ¤  ffffffa ¤  f ¤  fg ¤  fffa ¤  fff
  14. 14. 辞書順⽐比較の実装例例 ¤  ⾃自前で実装してもいいけど… ¤  Java ¤  a.compareTo(b) : a < b なら負の値が返る ¤  C++ ¤  a < b ¤  C ¤  strcmp(a, b) : a < b なら負の値が返る ¤  ⾃自分のよく使う⾔言語のライブラリは調べておこう
  15. 15. Problem C  ⾃自宅宅からの脱出 幅優先探索索
  16. 16. 問題 ¤  チェックポイントを通過した状態で、迷路路を抜ける最短時間 を求めたい。 ¤  例例 : 壁 スタート チェックポイント ゴール
  17. 17. ⽅方針 ¤  次のような探索索をやればOK ¤  スタートからチェックポイントまでの最⼩小時間 ¤  チェックポイントからゴールまでの最⼩小時間 ¤  答えは合計値、ただしどちらかが不不可能な場合は  -1 ¤  では、その最⼩小時間はどうやって求めるか?
  18. 18. ⽅方針 ¤  幅優先探索索 ¤  直前に⼿手を付けたところから東⻄西南北北に⾜足を伸ばしていく ¤  探索索済のマスにぶつかったら無視する
  19. 19. 幅優先探索索 ¤  スタートからチェックポイントに向かう場合を考える スタート チェックポイント 直前に⾒見見たところ 探索索済 Time = 0
  20. 20. 幅優先探索索 ¤  壁でない四⽅方をマークする スタート チェックポイント 直前に⾒見見たところ 探索索済 マーク Time = 1
  21. 21. 幅優先探索索 ¤  壁でない四⽅方をマークする、ただし探索索済のところは無視 スタート チェックポイント 直前に⾒見見たところ 探索索済 マーク Time = 2
  22. 22. 幅優先探索索 スタート チェックポイント 直前に⾒見見たところ 探索索済 マーク Time = 3
  23. 23. 幅優先探索索 スタート チェックポイント 直前に⾒見見たところ 探索索済 マーク Time = 4
  24. 24. 幅優先探索索 スタート チェックポイント 直前に⾒見見たところ 探索索済 マーク Time = 5
  25. 25. 幅優先探索索 スタート チェックポイント 直前に⾒見見たところ 探索索済 マーク Time = 6
  26. 26. 幅優先探索索 スタート チェックポイント 直前に⾒見見たところ 探索索済 マーク Time = 7
  27. 27. 幅優先探索索 発⾒見見! スタート チェックポイント 直前に⾒見見たところ 探索索済 マーク Time = 8
  28. 28. ⽅方針 ¤  必要な計算量量を⾒見見積もろう ¤  幅優先探索索を2回することになる ¤  1回あたり、全てのマスを調べるので O(NM) ¤  最⼤大 500 * 500 = 250,000 ¤  全体で 500,000 の処理理 ¤  変な実装をしちゃうと時間が掛かるので注意
  29. 29. int time = 0; bool[][] search; search[sy][sx] = true; bool[][] visited; visited[sy][sx] = true; while (true) { bool[][] next_search; time += 1; for (int i = 0 ; i < H ; i++) { for (int j = 0 ; j < W ; j++) { if (!search[i][j]) continue; // 4近傍を調べる。 // visited or 壁なら continue // その場所の  next_search を true に。 } } // } search = next_search; 実装例例1
  30. 30. int time = 0; この処理理に最⼤大500 * 500 = true; bool[][] search; search[sy][sx] = 250,000 最悪の場合・・・ bool[][] visited; visited[sy][sx] = true; while (true) { bool[][] next_search; time += 1; for (int i = 0 ; i < H ; i++) { for (int j = 0 ; j < W ; j++) { if (!search[i][j]) continue; // 4近傍を調べる。 // visited or 壁なら continue // その場所の  next_search を true に。 } } // } search = next_search; 実装例例1
  31. 31. 最悪のケース ##################################################### #SG.................................................# ###################################################.# #...................................................# #.################################################### #...................................................# ###################################################.# #...................................................# #.################################################### (中略略) #.################################################### #..................................................C# #####################################################
  32. 32. 幅優先探索索の実装 ¤  可変⻑⾧長配列列を使うとうまく実装できる ¤  Java : ArrayList<Integer> ¤  C++ : vector<int> ¤  使い⽅方は各⾃自調べてください。 ¤  マーク済みの座標を追加していく。 ¤  前回マークした位置を調べるには配列列の中⾝身を⾒見見る ¤  キューを使ってもいい ¤  Java : ArrayBlockingQueue<State> ¤  C++ : queue<State>
  33. 33. int time = 0; bool[][] visited; visited[sy][sx] = true; List<int> marks; marks.add(sy*1000+sx); while (true) { time += 1; List<int> next_marks; for (int state in marks) int i = state / 1000; int j = state % 1000; if (!search[i][j]) continue; // 4近傍を調べる。 // visited or 壁なら continue // 場所を  next_marks に追加。 } } } marks = next_marks; 実装例例2
  34. 34. Problem D  三⾓角パズル 動的計画法、メモ化再帰
  35. 35. 問題 ¤  直⾓角三⾓角形状に数字が並んでいる。 ¤  ⼀一番上の頂点から初めて、直下 or 右下  を選び下っていく ¤  途中通った数字の合計がスコアになる ¤  スコアの最⼤大値を求める ¤  例例: 3 8  9 4  7  6
  36. 36. ⽅方針 ¤  直下の最⼤大の数を選んでいけばmaxになるのでは? ¤  実はうまくいかない ¤  反例例 : sample 3 ¤  ⼤大きく分けて2つのアプローチ(本質的には同じ) ¤  ループで解く ¤  再帰で解く
  37. 37. ⽅方針1 : ループで解く ¤  ある段までの最⼤大値がわかっていたとする ¤  すると、次の段の最⼤大値も求められる bn,1 bn,2 … bn,n  ←最⼤大値 bn,1 bn,2 … bn,n bn+1,1 bn+1,n bn+1,n+1  ←最⼤大値 bn,i = 上から下って⾏行行って現在n段⽬目i列列⽬目にいるときの最⼤大値、とします
  38. 38. ⽅方針1 : ループで解く ¤  最⼤大値  bn,I = max(bn-1,I, bn-1,i-1) + an,i ¤  ただし、b1,1 = a1,1 ¤  ⼀一番上から順番に確定できる ¤  動的計画法 : ⼩小さな部分問題の解を使ってボトムアップ的に問 題の解を求める⼿手法 ¤  プログラミンコンテストではよく出てきます
  39. 39. ⽅方針2 : 再帰で解く ¤  再帰的に全ルートを調べることを考える ¤  現在地を (n,i)とおき ¤  (n+1,i)へ進む場合 ¤  (n+1,i+1)へ進む場合 ¤  を両⽅方調べ、どちらか⼤大きい⽅方 + an,I を返す ¤  しかし、この⽅方法だと N = 24〜~25 ぐらいが限界
  40. 40. ⽅方針2 : 再帰で解く/実装例例 function rec(int n, int i) { if (n >= N+1) return 0; int down = rec(n+1, i) + a[n][i]; int right = rec(n+1, i+1) + a[n][i]; int ret = max(down, right); return ret; }
  41. 41. ⽅方針2 : 再帰で解く f(1,1) f(2,1) f(2,2) f(3,1) f(3,2) f(3,2) f(3,3) f(4,1) f(4,2) f(4,2) f(4,3) f(4,2) f(4,3) f(4,3) f(4,4) f(5,2) f(5,3) f(5,3) f(5,4) f(5,3) f(5,4) f(5,2) f(5,3) f(5,2) f(5,3) f(5,3) f(5,4)
  42. 42. ⽅方針2 : 再帰で解く ¤  何故遅いか? ¤  同じ引数で関数が何度度も呼ばれるから。 ¤  重要な観察 : 同じ引数で呼ばれた関数は、必ず同じ値を返す ¤  ならば、⼀一度度計算した結果を覚えておいて、⼆二度度⽬目以降降は直接そ の値を返すようにしてしまおう ¤  メモ化再帰
  43. 43. ⽅方針2 : 再帰で解く/実装例例 int[][] memo; // -1で初期化済み function rec(int n, int i) { if (n >= N+1) return 0; if (memo[n][i] != -1) return memo[n][i]; int down = rec(n+1, i) + a[n][i]; int right = rec(n+1, i+1) + a[n][i]; int ret = max(down, right); memo[n][i] = ret; return ret; }
  44. 44. Problem E  会場への道 グラフ、ダイクストラ法
  45. 45. 問題 ¤  街と街をつなぐ道の情報が何個か与えられる ¤  0番街からN-1番街まで最短で⾏行行きたい。 ¤  ただし、到達時、時間が 4 か 7 で割り切切れなければならない ¤  例例: N = 6, M = 7 1 1 1 4 4 2 0 3 5 2 1 2 1
  46. 46. ⽅方針 ¤  グラフの最短経路路問題 ¤  ダイクストラ法(単⼀一始点最短路路) : O(MlogN) ¤  ワーシャルフロイド法(全点対最短路路) : O(N^3) ¤  まずは、条件を気にせずやってみよう ¤  (普通にダイクストラしてみる)
  47. 47. ダイクストラ法 ¤  各点までの所要時間をINF(⼗十分に⼤大きい値)に初期化 ¤  スタート地点を 0 に初期化 INF INF 1 1 4 1 4 2 0 0 2 3 1 5 1 INF INF 2 INF
  48. 48. ダイクストラ法 ¤  近い⽅方から確定していく。 1 INF 1 1 4 1 4 2 0 0 2 3 1 5 1 2 INF 2 INF
  49. 49. ダイクストラ法 1 3 1 1 4 1 4 2 0 0 2 3 1 5 1 2 3 2 3
  50. 50. ダイクストラ法 ¤  最短路路では答えは求まらない ¤  {街} を状態にして探索索した ¤  状態(◯の数)が⾜足りない ¤  では、状態を {街,時間} にしたらどうなる? 1 3 1 1 4 1 4 2 0 0 2 3 1 5 1 2 3 2 3
  51. 51. 状態を増やす ¤  このようなグラフでダイクストラをしてみれば・・・ 1,0 5,0 1,1 5,1 0,0 1,2 3,0 5,2 0,1 3,1 ・ 0,2 3,2 ・・・ ・ ・ ・ 2,0 3,3 ・ 5,7 ・ 2,1 3,4 ・ 3,5 ・ ・
  52. 52. 状態を増やす ¤  このようなことをすれば、確かに求まります ¤  しかし、状態数が膨⼤大になってしまう ¤  Nmax = 1,000 なので・・・ ¤  1,000 * 1,000,000 = 1,000,000,000 ¤  そもそも、状態を保持するメモリが確保できない ¤  状態は増やさなければならないが、これでは解けない。
  53. 53. 問題を簡単にしてみる ¤  到着時間の条件を「4で割り切切れる数値」にしてみる ¤  「4で割り切切れる数値」「7で割り切切れる数値」のそれぞれで 最⼩小を求め、答えはそのどちらか⼩小さい⽅方。
  54. 54. 問題を簡単にしてみる ¤  条件:「4で割り切切れる数値」で考える ¤  ある地点Aに、 ¤  36 で到達 ¤  40 で到達 ¤  なら、後者の場合は探索索しなくていい! ¤  どうしてか? ¤  気にすべきなのは、時間を4で割ったあまりのため。 ¤  A -> B (8経過) ¤  前者は Bに 44 で到達 ¤  後者は  Bに 48 で到達 (4で割ったあまりはAと変わらず)
  55. 55. 4で割った余りを考える 1,0 5,0 1,1 5,1 0,0 1,2 3,0 5,2 0,1 1,3 3,1 5,3 0,2 1,4 3,2 0,3 2,0 3,3 5,7 0,4 2,1 3,4 0,5 2,2 3,5 2,3 2,4
  56. 56. 4で割った余りを考える 1,0 5,0 1,1 5,1 0,0 1,2 3,0 5,2 0,1 1,3 3,1 5,3 0,2 3,2 0,3 2,0 3,3 2,1 2,2 2,3 {街,時間を4で割った余り} という状態にする
  57. 57. ⽅方針 ¤  頂点を4倍してダイクストラ ¤  {街,4で割った余り} = {N-1, 0} への最短到達時間を⾒見見る ¤  7で割り切切れる場合も同様に考え、頂点を7倍しダイクストラ ¤  {街,7で割った余り} = {N-1, 0} への最短到達時間を⾒見見る ¤  答えはそれらの最⼩小値 ¤  別解 ¤  頂点を 28 (=LCM(4,7))倍してダイクストラすると、⼀一気にできる
  58. 58. Problem F  最後の問題 累累積和
  59. 59. 問題 ¤  与えられた点のうち4点を選んで、⻑⾧長⽅方形を作る ¤  内部に点を含んではダメ ¤  辺の上にあるのはセーフ ¤  辺は軸と並⾏行行でなければダメ ¤  斜めってるのはNG ¤  作れる⻑⾧長⽅方形の中で、最⼤大の⾯面積を答える
  60. 60. 問題
  61. 61. :-(
  62. 62. :-(
  63. 63. :-)
  64. 64. ⽅方針 ¤  点の数が多い(N≦10,000)ため愚直にやってたら間に合わない ¤  4点の組合せを全て試す⽅方法では、N≦100 でも厳しい ¤  100^4 = 100,000,000 ¤  さらに内部に点を含むかの判定が必要 ¤  せめて、O(N^2)ぐらいのアルゴリズムがほしい。
  65. 65. ⽅方針 ¤  ⼊入⼒力力条件に着⽬目 ¤  0 ≦ xi ≦ 999、0 ≦ yi ≦ 999 ¤  指定された座標に点があるかどうか、配列列で保持できる ¤  重要な観察 : 対⾓角の2点が決まれば、⻑⾧長⽅方形が⼀一意に定まる ¤  2点を (xa, ya), (xb, yb) とおく ¤  もう2点は (xa, yb), (xb, ya) にある ¤  この2点に点があるかどうかは、配列列アクセスでO(1)で分かる ¤  残る問題は、内部に点があるかどうかの判定。 ¤  判定を O(1) でやりたい。
  66. 66. 解決策 ¤  各⻑⾧長⽅方形を調べる前に、次のような配列列を⽤用意する ¤  a[x][y] ¤  (0, 0)-(x, y)を対⾓角線とする⻑⾧長⽅方形に含まれる点の数 ¤  辺上の点も含む ¤  作り⽅方 ¤  1. aを0で初期化 ¤  2. 各点 (xi, yi) について、a[xi][yi] = 1 とおく ¤  3. 横に⼀一気に⾜足す ¤  4. 縦に⼀一気に⾜足す
  67. 67. イメージ
  68. 68. イメージ +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1
  69. 69. イメージ +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1
  70. 70. イメージ +1 +1 +1 +1 +1 +1 +1 +1 1 1 2 … 2 3 … 3 4 4 … 4
  71. 71. イメージ +1 +1 +1 +1 +1 +1 +1 +1 0 ……… 0 1 1 2 … 2 3 … 3 4 4 … 4
  72. 72. イメージ +1 +1 +1 +1 +1 0 ……… 0 1 … 1 2 2 … 3 ... 0 ……… 0 1 1 2 … 2 3 … 3 4 4 … 4
  73. 73. イメージ 0 0 … 0 1 1 1 … 1 2 ... 0 0 1 1 … 1 … 1 2 2 2 3 ... 0 ……… 0 1 … 1 2 2 … 3 ... 0 ……… 0 1 1 2 … 2 3 … 3 4 4 … 4
  74. 74. イメージ 0 0 … 0 1 1 1 … 1 2 ... 0 0 1 1 … 1 … 1 2 2 2 3 ... 0 ……… 0 1 … 1 2 2 … 3 ... 0 ……… 0 1 1 2 … 2 3 … 3 4 4 … 4
  75. 75. イメージ 1 0 … 0 1 1 1 … 1 2 ... 1 0 1 1 … 1 … 1 2 2 2 3 ... 1 ……… 0 1 … 1 2 2 … 3 ... 1 ……… 0 1 1 2 … 2 3 … 3 4 4 … 4
  76. 76. イメージ 1 1 2 6 6 6 … 9 12 ... 1 1 3 3 5 5 8 8 8 10 ... 1 2 4 4 6 6 … 7 ... 1 4 1 1 2 2 3 3 4 4 … 4
  77. 77. 数字の意味 1 1 2 6 6 6 9 12 1 1 3 3 5 5 8 8 8 10 6 6 7 4 4 4 4
  78. 78. 内部に点を含むか判定 1 1 2 6 6 6 9 12 1 1 3 3 5 5 8 8 8 10 1 2 4 4 6 6 7 1 4 1 1 2 2 3 3 4 4 4
  79. 79. 内部に点を含むか判定 1 1 2 6 6 6 9 12 1 1 3 3 5 5 8 8 8 10 1 2 4 4 6 6 7 1 4 1 1 2 2 3 3 4 4 4
  80. 80. 内部に点を含むか判定 5 8 4 6
  81. 81. 内部に点を含むか判定 5 8 4 6
  82. 82. 内部に点を含むか判定 5 8 =        - -        + 4 6 =8–5–6+4 =1
  83. 83. ⽅方針 ¤  N点のうち2点の組合せを調べる ¤  ⻑⾧長⽅方形ができるかどうか確かめる ¤  ⻑⾧長⽅方形ができる場合は、内部に点があるかどうか調べる ¤  累累積和を使うとこれがO(1)でできる ¤  全体で O(N^2) のアルゴリズム ¤  最⼤大で 10,000^2 = 100,000,000 で少し厳しい気もするが・・・ ¤  ⻑⾧長⽅方形の数⾃自体、そんなに多くできない ¤  制限時間5秒 ¤  うまくいきます
  84. 84. コンテストなどの紹介 ACM/ICPC, Topcoder, 早稲⽥田での勉強会
  85. 85. ACM/ICPC ¤  ⼤大学対抗プログラミングコンテスト ¤  3⼈人でチーム戦。留留年年してなければ修⼠士1年年まで参加可能 ¤  7/2 : 国内予選 ¤  11⽉月ぐらい : アジア地区予選 ¤  翌年年5⽉月ぐらい : 世界⼤大会 ¤  友だちを誘って出よう! ¤  ついこの前(5/17)、2012年年のWorld Finalが⾏行行われた ¤  東⼤大、京⼤大、電通⼤大が出場 ¤  東⼤大は11位に⼊入り、銅メダルを獲得した
  86. 86. Topcoder SRM ¤  定期開催型(⽉月2回ぐらい)のプログラミングコンテスト ¤  インターネットから参加可能 ¤  世界中の⼈人と競える! ¤  参加すると⾃自分の腕前を表すレーティングが付く
  87. 87. プログラミングコンテスト勉強会 ¤  毎週⽉月曜⽇日  9:30〜~ ¤  63号館  5階  05-23室(鷲崎研究室)

×