Problem:
通学経路

問題

太郎君の住んでいるJOI市は，南北方向にまっすぐに伸びる a 本の道路と，東西方向にまっすぐに伸びる b 本の道路により，碁盤の目の形に区分けされている．

南北方向の a 本の道路には，西から順に 1, 2, ... , a の番号が付けられている．また，東西方向の b 本の道路には，南から順に 1, 2, ... , b の番号が付けられている．西から i 番目の南北方向の道路と，南から j 番目の東西方向の道路が交わる交差点を (i, j) で表す．

太郎君は，交差点 (1, 1) の近くに住んでおり，交差点 (a, b) の近くのJOI高校に自転車で通っている．自転車は道路に沿ってのみ移動することができる．太郎君は，通学時間を短くするため，東または北にのみ向かって移動して通学している．

現在， JOI市では， n 個の交差点 (x1, y1), (x2, y2), ... , (xn, yn) で工事を行っている．太郎君は工事中の交差点を通ることができない．

太郎君が交差点 (1, 1) から交差点 (a, b) まで，工事中の交差点を避けながら，東または北にのみ向かって移動して通学する方法は何通りあるだろうか．太郎君の通学経路の個数 m を求めるプログラムを作成せよ．

入力

入力は複数のデータセットからなる．各データセットは以下の形式で与えられる．入力はゼロを２つ含む行で終了する．

1行目には，空白を区切りとして2個の整数 a, b が書かれている．これは，南北方向の道路の本数と，東西方向の道路の本数を表す． a, b は 1 ≤ a, b ≤ 16 をみたす．

2行目には, 工事中の交差点の個数を表す整数 n が書かれている． n は 1 ≤ n ≤ 40 をみたす．

続く n 行 (3行目から n+2 行目) には，工事中の交差点の位置が書かれている． i+2 行目には空白で区切られた整数 xi, yi が書かれており，交差点 (xi, yi) が工事中であることを表す． xi, yi は 1 ≤ xi, yi ≤ 16 をみたす．

データセットの数は 5 を超えない．

出力

データセットごとに, 太郎君の通学経路の個数 m を1行に出力する．

入出力例

入力例

5 4
3
2 2
2 3
4 2
5 4
3
2 2
2 3
4 2
0 0

出力例

5
5

下図は a=5, b=4, n=3 で，工事中の交差点が (2,2), (2,3), (4,2) の場合を表している．

この場合，通学経路は m=5 通りある． 5通りの通学経路を全て図示すると，以下の通り．

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

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using static System.Math;
using static System.Array;
using static AtCoder.Tool;
namespace AtCoder
{
    class AC
    {
        const int MOD = 1000000007;
        const int INF = int.MaxValue / 2;
        const long SINF = long.MaxValue / 2;
        const double EPS = 1e-8;
        static readonly int[] dx = { 0, 1, 0, -1 };
        static readonly int[] dy = { 1, 0, -1, 0 };

        
        static void Main(string[] args)
        {
            //var sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
            //Console.SetOut(sw);
            var cin = new Scanner();

            while (true)
            {
                var input = cin.SplitRead();
                int a = input[0];
                int b = input[1];
                if (a == 0 && b == 0) { return; }
                int n = int.Parse(Console.ReadLine());
                var map = new char[a, b];
                var seen = new bool[a, b];
                for (var i = 0; i < a; i++)
                {
                    for (var j = 0; j < b; j++)
                    {
                        map[i, j] = '.';
                        seen[i, j] = false;
                    }
                }
                for (var i = 0; i < n; i++)
                {
                    var wall = cin.SplitRead();
                    map[wall[0] - 1, wall[1] - 1] = '#';
                }

                var dp = new long[a, b];
                for (var i = 0; i < a; i++)
                {
                    for (var j = 0; j < b; j++)
                    {
                        dp[i, j] = i == 0 && j == 0 ? 1 : 0;
                    }
                }

                var bfs = new Queue<Tuple<int, int>>();
                bfs.Enqueue(new Tuple<int, int>(0, 0));

                while (bfs.Count() > 0)
                {
                    var q = bfs.Dequeue();
                    //Console.WriteLine(q);
                    int x = q.Item1;
                    int y = q.Item2;
                    
                    if (x < a - 1)
                    {
                        if (map[x + 1, y] == '.') { dp[x + 1, y] += dp[x, y]; }
                        if (!seen[x + 1, y])
                        {
                            bfs.Enqueue(new Tuple<int, int>(x + 1, y));
                            seen[x + 1, y] = true;
                        }
                    }
                    if (y < b - 1)
                    {
                        if (map[x, y + 1] == '.') { dp[x, y + 1] += dp[x, y]; }
                        if (!seen[x, y + 1])
                        {
                            bfs.Enqueue(new Tuple<int, int>(x, y + 1));
                            seen[x, y + 1] = true;
                        }
                    }
                }

                /*for (var i = 0; i < a; i++)
                {
                    for (var j = 0; j < b; j++)
                    {
                        Console.Write($"{dp[i, j]} ");
                    }
                    Console.WriteLine();
                }*/
                Console.WriteLine(dp[a - 1, b - 1]);
            }

            //Console.Out.Flush();
        }

    }

   

    

    

    public class Scanner
    {
        public int[] SplitRead()
        {
            int[] array = Console.ReadLine().Split().Select(int.Parse).ToArray();
            return array;
        }
        public long[] SplitReadL()
        {
            long[] array = Console.ReadLine().Split().Select(long.Parse).ToArray();
            return array;
        }
    }

    public static class Tool
    {
        static public void Initialize<T>(ref T[] array, T initialvalue)
        {
            for (var i = 0; i < array.Length; i++)
            {
                array[i] = initialvalue;
            }
        }
    }
}