Super Jaber【最短路】

Super Jaber

 CodeForces - 1301F


  题意:有N*M的一个网格图,每一个格子都是代表一个点,每个点都有自己的颜色,每个点都可以走到邻近的某个点,也可以是直接利用跳转,跳转到颜色相同的点,现在,给出Q组询问,我们想知道从(sx,sy)到(ex,ey)的最短路有多长。

  思路:因为这里的颜色数很少,所以很容易想到是跳颜色这样一个做法,如果说不跳颜色的话,那么就是二者的曼哈顿距离了,这肯定是可以O(1)计算得到的,接下去考虑的肯定就是需要跳转这样的一个做法了,因为颜色足够的少,所以我们不妨从颜色角度来考虑,考虑以中间哪个颜色作为跳板。

  既然要用中间的某个颜色作为跳板的话,那么,这个颜色肯定是跳了的,那么就是需要知道的是这个颜色到其余各点的距离了,这个可以通过O(K*N*M)的BFS搜索来求得。中间需要剪枝,每个其余的颜色都是只能作为跳板一次,因为不可避免的是有时候的最短路,得从中间做一个跳板,但是每个颜色最多使用一次,这里需要剪枝,不然就会像我一样TLE on TEST 9。

  那么,这样做的正确性来源于哪里呢?首先不需要任何跳板,我们直接走曼哈顿距离的正确性显而易见,其次就是需要跳板的时候了,既然需要跳板,那么就是dis[col][sx][sy] + dis[col][ex][ey] + 1。有些col点并没有跳,甚至有些col点要是跳的话反而更远了,但是别忘了我们这里的查的部分是“必须有跳的”,那么K种颜色中必定是有一个颜色作为了这个跳板,并且还是最短路径上的一个必经之路,于是,这里的正确性就显现出来了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
#define MIN(a, b) a > b ? b : a
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int dir[4][2] =
{
    -1, 0,
    0, -1,
    1, 0,
    0, 1
};
int N, M, K, a[1005][1005], Ques;
inline bool In_Map(int x, int y) { return x >= 1 && y >= 1 && x <= N && y <= M; }
vector<pair<int, int>> col[45];
bool vis_col[45], vis_point[1005][1005];
short int dis[45][1005][1005];
queue<pair<int, int>> Q;
pair<int, int> now;
inline void bfs(int id)
{
    for(int i=1; i<=N; i++) for(int j=1; j<=M; j++) { dis[id][i][j] = 2020; vis_point[i][j] = false; }
    for(int i=1; i<=K; i++) vis_col[i] = false;
    int len = (int)col[id].size(); vis_col[id] = true;
    for(int i=0, x, y; i<len; i++)
    {
        x = col[id][i].first; y = col[id][i].second;
        dis[id][x][y] = 0;
        vis_point[x][y] = true;
        Q.push(MP(x, y));
    }
    int x, y, xx, yy;
    while(!Q.empty())
    {
        now = Q.front(); Q.pop();
        x = now.first; y = now.second;
        if(!vis_col[a[x][y]])
        {
            vis_col[a[x][y]] = true;
            len = (int)col[a[x][y]].size();
            for(int i=0; i<len; i++)
            {
                xx = col[a[x][y]][i].first; yy = col[a[x][y]][i].second;
                if(vis_point[xx][yy]) continue;
                vis_point[xx][yy] = true;
                dis[id][xx][yy] = dis[id][x][y] + 1;
                Q.push(MP(xx, yy));
            }
        }
        for(int i=0; i<4; i++)
        {
            xx = x + dir[i][0]; yy = y + dir[i][1];
            if(!In_Map(xx, yy) || vis_point[xx][yy]) continue;
            vis_point[xx][yy] = true;
            dis[id][xx][yy] = dis[id][x][y] + 1;
            Q.push(MP(xx, yy));
        }
    }
}
int main()
{
    scanf("%d%d%d", &N, &M, &K);
    for(int i=1; i<=N; i++) for(int j=1; j<=M; j++) { scanf("%d", &a[i][j]); col[a[i][j]].push_back(MP(i, j)); }
    for(int i=1; i<=K; i++) bfs(i);
    short int sx, sy, ex, ey, ans;
    scanf("%d", &Ques);
    while(Ques--)
    {
        scanf("%hd%hd%hd%hd", &sx, &sy, &ex, &ey);
        ans = abs(sx - ex) + abs(sy - ey);
        for(int i=1; i<=K; i++) ans = MIN(ans, dis[i][sx][sy] + dis[i][ex][ey] + 1);
        printf("%hd\n", ans);
    }
    return 0;
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值