Problem:
散歩

問題

JOI 町に住む太郎君は, ある日,健康増進のために散歩を日課にしようと思い立った.
太郎君の住む JOI 町には,図のように,東西方向に走る (H + 1) 本の道路と,南北
方向に走る (W + 1) 本の道路が碁盤目状に通っている.太郎君の家はもっとも北西の
交差点にあり,ここから散歩を開始する.

以降,北から a 番目,西から b 番目の交差点を (a, b) で表す.たとえば,太郎君の家がある交差点は (1, 1) である.

図: JOI 町の図 (H = 3, W = 4 の場合).図の上が北,左が西に対応する.

太郎君は,散歩のルートが日々違ったほうが面白いと考えたので,(1, 1) から (H, W) までの H × W 個の交差点に, 「東」または「南」の文字を書き,次のようなルールに従って毎日散歩を行うことにした.

文字の書かれた交差点にいる場合,その交差点に書かれている文字が「東」な
ら「南」に, 「南」なら「東」に文字を書き換え,もともと書かれていた文字の方角にある次の交差点まで進む.

もっとも東やもっとも南の道路に到達したら散歩を終了する.

この計画を考えた後,太郎君は,将来の散歩で自分がどのようなルートをたどる
ことになるのかが気になった.太郎君のために,太郎君の N 回目の散歩のルートを
予測するプログラムを作成せよ.

入力

入力は複数のデータセットからなる．各データセットは以下の形式で与えられる．

1 行目には,3 つの正整数が空白区切りで書かれている.これらは,問題文中の 3 つの数値 H, W, N の値である. H, W, N はそれぞれ, 1 ≤ H ≤ 1000, 1 ≤ W ≤ 1000, 1 ≤ N ≤ 10000000 = 107 をみたす. 2 行目から H + 1 行目には,それぞれ W 個の整数が空白区切りで書かれている.これらは,太郎君が最初に交差点に書いた文字の情報を表す. i + 1 行目の j 番目の整数が 0 なら,交差点 (i, j) に書かれた文字が「南」であることを, 1 なら, 交差点 (i, j) に書かれた文字が「東」であることを表す.

採点用データのうち,配点の 30%分については, H ≤ 100, W ≤ 100, N ≤ 1000 を満たす.

H, W, N がすべて 0 のとき入力の終了を示す. データセットの数は 10 を超えない．

出力

データセットごとに次の形式で出力する.

N 回目の散歩において太郎君が散歩を終了する交差点が (i, j) のとき,i と j をこの順に空白で区切って出力せよ.

入出力の例

入力例

3 4 3
1 0 1 1
0 1 0 0
1 0 1 0
0 0 0

出力例

1 5

上の例では,1 回目から 3 回目の散歩のルートは次の図のようになる.

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in C++ (judge verdict: Accepted)

#include <bits/stdc++.h>
 
using namespace std;
 
#define MAX 1010
 
bool a[MAX][MAX];
int dp[MAX][MAX];
int H, W;
 
bool get_dir(int n, bool dir)
{
    return (n % 2 == 0 ? dir : !dir);
}
 
void find_last_point()
{
    int x = 0, y = 0;
    while (true) {
        if (a[y][x] == 1) {
            x++;
        } else {
            y++;
        }
        if (x >= W || y >= H) break;
    }
    cout << y+1 << " " << x+1 << endl;
}
 
int main()
{
    int N;
    while (cin >> H >> W >> N, H) {
        for (int i = 0; i < H; i++) {
            for (int j = 0; j < W; j++) {
                cin >> a[i][j];
            }
        }

        memset(dp, 0, sizeof(dp));
        dp[0][0] = N-1;

        for (int i = 0; i < H; i++) {
            for (int j = 0; j < W; j++) {
                if (dp[i][j] == 0) continue;
                a[i][j] = get_dir(dp[i][j], a[i][j]);
                if (dp[i][j] % 2 == 1) {
                    if (a[i][j] == 0) {
                        dp[i+1][j] += dp[i][j] / 2;
                        dp[i][j+1] += dp[i][j] / 2 + 1;
                    } else {
                        dp[i+1][j] += dp[i][j] / 2 + 1;
                        dp[i][j+1] += dp[i][j] / 2;
                    }
                } else {
                    dp[i+1][j] += dp[i][j] / 2;
                    dp[i][j+1] += dp[i][j] / 2;
                }
            }
        }
        find_last_point();
    }
    return 0;
}