Space pirate Captain Krys has recently acquired a map of the artificial and highly secure planet Alpha-Zet which he has been planning to raid for ages. It turns out the whole planet is built on a 2D plane with modules that serve as one room each. There is exactly one module at every pair of integer coordinates and modules are exactly 1 × 1 units big. Every module is bidirectionally connected to at least one adjacent module. Also, for any two modules there exists exactly one path between them. All in all the modules create a rectangular maze without any loops.
Figure A.1: Illustration of Sample Input 2
On the map Captain Krys has marked several modules he wants to visit in exactly the marked order. What he intends to do there is none of your business, but he promises you a fortune if you determine the number of modules he has to walk through along
the route (since there are no loops he will always take the direct route from one marked module to the next). The first marked module indicates where he starts his journey, the last where he wants to finish.
The input consists of:
?one line with two integers h and w (2 ≤ h, w ≤ 1 000) describing the height and the width of the maze.
?h + 1 lines follow, describing the maze in ASCII, each line containing 2 · w + 1 characters.
The description always follows these rules:
–In every row, columns with odd index (starting at index 1) contain either vertical walls or spaces and columns with even index contain either horizontal walls or spaces.
–The first row describes the northern wall of the maze (which always consists only of horizontal walls). Every subsequent row describes a row of modules.
–A module is located at every even column index. Its western and eastern walls are located at the directly neighboring odd column indices respectively, its northern wall is located at the same column index but one row above and its southern wall can be found at its own position. If a wall is missing, the corresponding position contains a space instead.
?After the description of the maze, an integer m (2 ≤ m ≤ 104) is given.
?Each of the following m lines describes a marked module with two integer coordinates x and y (1 ≤ x ≤ h; 1 ≤ y ≤ w). The first pair of coordinates is the start point of the journey, the last pair the end point. Modules may appear multiple times but never twice or more in a row. (1, 1) is the top left module and (h, w) is the bottom right module.
It is guaranteed that the maze itself is enclosed. Furthermore it is guaranteed that exactly one path exists between any two modules.
Output one integer, the number of modules Captain Krys has to travel through if he follows the route in the exact order given in the input.
GCPC2018
题意:给你一个n*m的矩阵,保证了两点之间一定只有一条路使之连通,再给你接下来要走的点的顺序,问最短需要多少的长度?
做法:首先我们需要处理输入,输入n*m的矩阵,实则输入的是一个(n+1)*(2*m+1)的矩阵,像是模拟一样的,给每个间隙hash一下编个号,于是根据原图的联通性可以将编号构成一棵无向树,知道了每一步的坐标,由上一步走到这一步,在无向树上一定是先走到lca再走到下一个节点最近,于是问题就转化成了树上两点之间最近距离,于是lca写一下就过了。
吐槽自己的lca模板 已撕掉
代码如下:
/*
_ _ _ _ _ _
| _ _ _ _ _|
|_ _ _ _ _ _|
0123456789*
5 5
_ _ _ _ _
|_ _ |_ |
| _| | _|
| |_ _| |
| _ _ |
|_|_ _ _|_|
7
4 4
1 4
3 1
4 5
1 2
2 2
5 4
n+1行 2*m+1列
2 4
_ _ _ _
| _ _ _|
|_ _ _ _|
2018.9.7
第一法超时是本人的LCA模板不够友好 于是Flower现在更换模板
*/
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#define rep(i , j , k) for(int i=j; i<=k; i++)
using namespace std;
const int maxn = 1005;
const int maxm = 2005;
int n , m;
char mp[maxn][maxm];
struct EDGE
{
int to , next;
}edge[maxn*maxn*2];
int head[maxn*maxn];
int tot;
int father[20][maxn*maxn] , depth[maxn*maxn]; ///20是log(maxn)的大小
void init1()
{
memset(head , -1, sizeof(head));
tot = 0;
}
void add(int u , int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void input()
{
getchar();
for(int i=0; i<=n; i++)
{
gets(mp[i]);
}
}
int num(int i , int j)
{
i = i-1;
j = (j+1)/2;
return i*m+j;
}
void build()
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=2*m; j+=2)
{
if(mp[i][j+1] != ‘|‘)
{
///和右边的可以互通
add(num(i,j) , num(i,j+2));
add(num(i,j+2) , num(i,j));
}
if(mp[i][j] != ‘_‘)
{
///和下面可以互通
add(num(i,j) , num(i+1,j));
add(num(i+1,j) , num(i,j));
}
}
}
}
void dfs(int u , int f)
{
father[0][u] = f;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
int v = edge[i].to;
if( v == f) continue;
depth[v] = depth[u]+1;
dfs(v , u);
}
}
void init(int N)
{
depth[1] = 1;
dfs(1,-1);
for(int i=1; i<20; i++) ///20不带等号
{
for(int j=1; j<=N; j++)
{
father[i][j] = father[i-1][father[i-1][j]];
}
}
}
int lca(int x , int y)
{
if(depth[x] > depth[y]) swap(x , y);
for(int i=0; i<20; i++)
{
if((depth[y]-depth[x])>>i&1)
y = father[i][y];
}
if(x == y) return x;
for(int i=19; i>=0; i--)
{
if(father[i][x] != father[i][y])
{
x = father[i][x];
y = father[i][y];
}
}
return father[0][x];
}
void judge()
{
for(int i=1; i<=n*m; i++)
{
printf("%d..%d..\n" , i , depth[i]);
}
}
void solve()
{
// judge();
long long res = 0;
int a , b , tmp1 , tmp2 , q , tmp3;
scanf("%d" , &q);
for(int i=1; i<=q; i++)
{
scanf("%d%d" , &a , &b);
tmp2 = num(a , b*2-1);
if(i != 1)
{
tmp3 = lca(tmp1 , tmp2); ///tmp3来记录tmp1与tmp2的LCA 现在图已经建好了 节点编号是1~n*m 链表存图 求LCA
res += ((depth[tmp1]-depth[tmp3])+(depth[tmp2]-depth[tmp3]));
}
tmp1 = tmp2;
}
printf("%lld\n" , res);
}
void debug()
{
for(int i=0; i<=n*m; i++)
{
printf("%d+++++++++++\n" , i);
for(int j=head[i]; j!=-1; j=edge[j].next)
{
printf("%d " , edge[j].to);
}
printf("\n");
}
}
int main()
{
while( scanf("%d%d" , &n , &m) != EOF )
{
init1();
input();
build();
///到这里终于把无向树建出来了
init(n*m);
// debug();
solve();
}
return 0;
}