Problem:
全探索お姉さんの休日

全探索お姉さんはとても優秀な女性である。
お姉さんは格子状の道の経路の数え上げを数千程度なら簡単に数え上げてしまう。

あなたと全探索お姉さんは今、六角形のタイルが敷き詰められた部屋にいる。
お姉さんは初めて見る六角形にとても興奮している様子である。
六角形の並びを座標に表すことに不慣れなお姉さんは図1のような座標系で部屋を表した。

図1

あなたはこの座標系上である地点からある地点まで移動したい。
しかし、お姉さんは 1 分ごとに動きたい方向をあなたに指示する。
いつものお姉さんなら同じ座標の場所を通らないようにあなたに移動の指示を出すだろう。
しかし、この座標系に不慣れなお姉さんは|x×y×t|(x：x 座標、y：y座標、t:最初の指示からの経過時間[分])を 6 で割った余り
に対応する方向（図で示す番号と対応）を指示するだけで、まったくのでたらめな方向にあなたを誘導する。

図2

お姉さんを傷つけたくないあなたは、お姉さんの指示をできるだけ守りつつ目的地までたどり着きたい。
あなたは許された行動は下の 7 つの行動である。

方向 0 へ 1 タイル移動

方向 1 へ 1 タイル移動

方向 2 へ 1 タイル移動

方向 3 へ 1 タイル移動

方向 4 へ 1 タイル移動

方向 5 へ 1 タイル移動

その場に留まる

お姉さんが指示を出した直後にあなたはこれら行動のうちの必ず1つを行う。

部屋には家具があり家具が配置されているタイルの中に移動することはできない。
また、y 座標の絶対値が ly を超えたり x 座標の絶対値が lx を超えるような移動は許されていない。
しかし、お姉さんはそのような移動を指示することがある。
指示を無視するとはお姉さんが示した方向と異なる方向へ移動するか、
もしくは、その場に留まることである。

目的地にたどり着くために最小で何度指示を無視すれば良いかを出力せよ。
目的地にたどり着くことが不可能な場合は -1 を出力せよ。

Input

入力は以下の形式で与えられる。

sx sy gx gy
n
x1 y1
...
xi yi
...
xn yn
lx ly

ここで、

sx, sy は出発地点の座標

gx, gy は目的地の座標

n は部屋に配置されている家具の数

xi, yi は家具があるタイルの座標

lx, ly は移動できる X, Y それぞれの座標の絶対値の上限
である。

Constraints

入力はすべて整数

-lx ≤ sx, gx ≤ lx

-ly ≤ sy, gy ≤ ly

(sx, sy) ≠ (gx, gy)

(xi, yi) ≠ (sx, sy)(1≤i≤n)

(xi, yi) ≠ (gx, gy)(1≤i≤n)

(xi, yi) ≠ (xj, yj)(i ≠ j)

0≤ n ≤ 1000

-lx ≤ xi ≤ lx (1≤i≤n)

-ly ≤ yi ≤ ly (1≤i≤n)

0 < lx, ly ≤ 100

Output

出力は1つの整数を含む1行で出力せよ。
目的地にたどり着ける場合は、最小の指示を無視する回数を出力せよ。
目的地にたどり着くことが不可能な場合は-1を出力せよ。

Sample Input 1

0 0 0 2
0
2 2

Output for the Sample Input 1

0

Sample Input 2

0 0 0 2
6
0 1
1 0
1 -1
0 -1
-1 -1
-1 0
2 2

Output for the Sample Input 2

-1

Sample Input 3

0 0 0 2
1
0 1
2 2

Output for the Sample Input 3

1

Solution in C++ (judge verdict: Accepted)


#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <algorithm>
#include <numeric>
#include <functional>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <climits>
using namespace std;

typedef istringstream ISS;
typedef ostringstream OSS;
typedef vector<string> VS;
typedef int INT;
typedef vector<INT> VI;
typedef vector<VI> VVI;
typedef pair <INT, INT> II;
typedef vector <II> VII;


typedef pair <int, II> STATE; 
typedef pair <int, STATE> NODE; 
typedef priority_queue <NODE, vector<NODE>, greater<NODE> > QUEUE;
typedef map <STATE, int> MIN_COST;
typedef set<II> HASH;
const int OBJECT_NUMBER = 1001;
const int MOD = 6;
const int NONE = -1;

const int dr[2][7] = {
    { 1, 0, -1, -1, -1, 0, 0 },
    { 1, 1, 0, -1, 0, 1, 0 }
};
const int dc[2][7] = {
    { 0, 1, 1, 0, -1, -1, 0 },
    { 0, 1, 1, 0, -1, -1, 0 }
};

int sr, sc, gr, gc; 
int n;
int R[OBJECT_NUMBER]; 
int C[OBJECT_NUMBER];
int H, W; 

MIN_COST MC; 
QUEUE Q;
HASH OBJ;

void init() {
    OBJ.clear();
    for ( int i = 0; i < n; ++ i ) {
        OBJ.insert( II( R[i], C[i] ) );
    }
}

bool input() {
    if ( ! ( cin >> sc >> sr >> gc >> gr ) ) return false;
    cin >> n;
    for ( int i = 0; i < n; ++ i ) {
        cin >> C[i] >> R[i];
    }
    cin >> W >> H;
    return true;
}

bool is_min_cost( int cost, STATE state ) {
    return MC.count(state) ? cost < MC[state] : true;
}

int solve() {
    Q = QUEUE();
    MC.clear();
    STATE start_state( 0, II( sr, sc ) );
    Q.push( NODE( 0, start_state ) );
    MC[start_state] = 0;

    while ( ! Q.empty() ) {
        NODE node = Q.top();
        Q.pop();

        int cost = node.first;
        int steps = node.second.first;
        int r = node.second.second.first;
        int c = node.second.second.second;

        if ( r == gr && c == gc ) return cost;

        for ( int i = 0; i < 7; ++ i ) {
            int free_dir = abs( r * c * steps ) % MOD;
            int new_cost = cost + ( i == free_dir ? 0 : 1 );
            
            int d_type = c % 2 == 0 ? 0 : 1;
            int nr = r + dr[d_type][i];
            int nc = c + dc[d_type][i];
            II new_pos( nr, nc );
            if ( abs(nr) > H || abs(nc) > W ) continue;
            if ( OBJ.count( new_pos ) ) continue;
            
            int new_steps = ( steps + 1 ) % MOD;
            STATE new_state( new_steps, new_pos );
            if ( ! is_min_cost( new_cost, new_state ) ) continue;
            MC[new_state] = new_cost;
            
            Q.push( NODE( new_cost, new_state ) );
        }
    }

    return NONE;
}

int main() {
    while ( input() ) {
        init();
        cout << solve() << endl;
    }
    return 0;
}