Codeforces Round #420 (Div. 2) 821D Okabe and City 思维建图+spfa

Okabe likes to be able to walk through his city on a path lit by street lamps. That way, he doesn't get beaten up by schoolchildren.

Okabe's city is represented by a 2D grid of cells. Rows are numbered from 1 to nfrom top to bottom, and columns are numbered 1 to m from left to right. Exactly kcells in the city are lit by a street lamp. It's guaranteed that the top-left cell is lit.

Okabe starts his walk from the top-left cell, and wants to reach the bottom-right cell. Of course, Okabe will only walk on lit cells, and he can only move to adjacent cells in the up, down, left, and right directions. However, Okabe can also temporarily light all the cells in any single row or column at a time if he pays 1coin, allowing him to walk through some cells not lit initially.

Note that Okabe can only light a single row or column at a time, and has to pay a coin every time he lights a new row or column. To change the row or column that is temporarily lit, he must stand at a cell that is lit initially. Also, once he removes his temporary light from a row or column, all cells in that row/column not initially lit are now not lit.

Help Okabe find the minimum number of coins he needs to pay to complete his walk!

Input

The first line of input contains three space-separated integers nm, and k (2 ≤ n, m, k ≤ 104).

Each of the next k lines contains two space-separated integers ri and ci (1 ≤ ri ≤ n,1 ≤ ci ≤ m) — the row and the column of the i-th lit cell.

It is guaranteed that all k lit cells are distinct. It is guaranteed that the top-left cell is lit.

Output

Print the minimum number of coins Okabe needs to pay to complete his walk, or -1 if it's not possible.

Example
Input
4 4 5
1 1
2 1
2 3
3 3
4 3
Output
2
Input
5 5 4
1 1
2 1
3 1
3 2
Output
-1
Input
2 2 4
1 1
1 2
2 1
2 2
Output
0
Input
5 5 4
1 1
2 2
3 3
4 4
Output
3
Note

In the first sample test, Okabe can take the path , paying only when moving to (2, 3) and(4, 4).

In the fourth sample, Okabe can take the path  , paying when moving to (1, 2)(3, 4), and (5, 4).



思路:题目中给了已经点亮的点,那么从任何亮着的点出发,假如(x ,y)人可以到达相邻的亮着的点,或者去某行某列,x+1,x,x-1,y+1,y,y-1,同样 相应行列也能进入改点并且没有花费。但是要注意,右下角可能亮着灯,也可能不亮,需要考虑一下。


#include <cstdio>
#include <queue>
#include <map>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll inf = 1e14;
ll m,n,k;
struct node{
   ll to,v;
};
vector <node> side[100005];
void add(ll x,ll y, ll v)
{
    side[x].push_back((node){y,v});
}
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
int inq[50005];
ll dis[50005];
void spfa(int be)
{
    memset(inq,0,sizeof(inq));
    for(int i = 1; i <= n+m+k+1; i++)
        dis[i] = i==be? 0 : inf ;
    queue <ll > q;
    q.push(be);
    while(!q.empty())
    {
        int tmp = q.front();
        q.pop();
        inq[tmp] = 0;
        for(int i = 0; i < side[tmp].size();i++)
        {
            ll y = side[tmp][i].to;
            ll v = side[tmp][i].v;
            if(dis[tmp] + v < dis[y])
            {
                dis[y] = dis[tmp]+ v;
                if(!inq[y])
                {
                    inq[y] = 1;
                    q.push(y);
                }
            }
        }
    }
}
ll x[10010],y[10010];
map<int,int>mp[10010];
int main()
{
    scanf("%lld%lld%lld",&m,&n,&k);
    for(int i = 1; i <= k; i++)
    {
        scanf("%lld%lld",&x[i],&y[i]);
        mp[x[i]][y[i]] = i;
    }
    for(int i = 1; i <= k; i++)
    {
        for(int j = 0; j < 4; j++)
        {
            int x_ = x[i] + dir[j][0];
            int y_ = y[i] + dir[j][1];
            if(mp[x_][y_]&&x_>0&&y_>0&&x_<=m&&y_<=n)
            {
                add(i+m+n,mp[x_][y_]+m+n,0);
            }
        }
        if(!mp[m][n])
        {
            add(m,m+n+k+1,0);
            add(m+n,m+n+k+1,0);
        }
        else
        {
            add(mp[m][n]+m+n,m+n+k+1,0);
        }
        if(x[i]+1<=m)
        {
            add(i+m+n,x[i]+1,1);
            add(x[i]+1,i+m+n,0);
        }
        if(x[i]-1>=1)
        {
            add(i+m+n,x[i]-1,1);
            add(x[i]-1,i+m+n,0);
        }
        add(m+n+i,x[i],1);
        add(x[i],m+n+i,0);
        if(y[i]+1<=n)
        {
            add(i+m+n,y[i]+m+1,1);
            add(y[i]+m+1,i+m+n,0);
        }
          if(y[i]-1>=1)
        {
            add(i+m+n,y[i]+m-1,1);
            add(y[i]+m-1,i+m+n,0);
        }
        add(m+n+i,y[i]+m,1);
        add(y[i]+m,m+n+i,0);
    }
    spfa(m+n+1);
    ll ans = dis[m+n+k+1];
    if(ans == inf) printf("-1");
    else     printf("%I64d",ans);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值