Codeforces 1301F - Super Jaber(思维+BFS)

题意

n ∗ m n*m nm的地图上,每个格子有一个颜色。最多 k k k种颜色。每次可以花费 1 1 1时间去相邻格子,或者花费 1 1 1时间跳到相同颜色格子。 Q Q Q次查询 ( x 1 , y 1 ) , ( x 2 , y 2 ) (x1,y1), (x2,y2) (x1,y1),(x2,y2)问从 ( x 1 , y 1 ) (x1,y1) (x1,y1) ( x 2 , y 2 ) (x2,y2) (x2,y2)最少时间为多少。

n , m ≤ 1000 , Q ≤ 1 e 5 , k ≤ 40 n,m\le 1000,Q\le 1e5,k\le 40 n,m1000,Q1e5,k40

解题思路

从起点到终点,两种可能:

  1. 没有跳。答案为曼哈顿距离。
  2. 跳了。枚举跳的颜色。需要知道从当前点到指定颜色最少花费。

现在要求从某个点到指定颜色的最小花费。因为是无向图,所以可以预处理每个颜色到所有点的最小花费。这里使用0-1 BFS一直TLE。其实只用简单BFS就可以了,到达某个没去过的颜色,就把所有同色的没去过的颜色染色。

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define fors(i, a, b) for(int i = (a); i < (b); ++i)
#define P pair<int,int>
using namespace std;
int n, m, k;
void read(int &x){
    char ch = getchar(); x = 0;
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch <= '9' && ch >= '0') x = (x<<3)+(x<<1)+(ch^'0'), ch = getchar();
    return;
}
bool in(int x, int y){
    if(x < 0 || x >= n || y < 0 || y >= m) return false;
    return true;
}
const int maxn = 1e6 + 42;
int dis[40][maxn];
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};
vector<int> g[maxn], o[40];
queue<int> q;
int col[40], a[maxn];
void bfs(int st, int *vis){
    memset(col, 0, sizeof col);
    col[st] = 1;
    for(int v: o[st]) vis[v] = 1, q.push(v);
    while(q.size()){
        int u = q.front(); q.pop();
        if(!col[a[u]]){
            col[a[u]] = 1;
            for(int v: o[a[u]]) if(!vis[v]) vis[v] = vis[u]+1, q.push(v);
        }
        for(int v: g[u]) if(!vis[v]) vis[v] = vis[u]+1, q.push(v);
    }
}
void init(){
    scanf("%d%d%d", &n, &m, &k);
    fors(i, 0, n*m){
        int c; read(c); a[i] = c-1;
        int x = i/m, y = i%m;
        fors(j, 0, 4){
            if(in(x+dx[j], y+dy[j])){
                int p = (x+dx[j])*m+y+dy[j];
                g[i].pb(p);
            }
        }
        o[c-1].pb(i);
    }
    fors(i, 0, k) bfs(i, dis[i]);
}
void sol(){
    int Q; cin>>Q;
    while(Q--){
        int x1, y1, x2, y2;
        read(x1); read(y1); read(x2); read(y2);
        x1--; y1--; x2--; y2--;
        int ans = abs(x2-x1)+abs(y2-y1);
        int p1 = x1*m+y1, p2 = x2*m+y2;
        fors(i, 0, k){
            if(!dis[i][p1]) continue;
            ans = min(dis[i][p1]+dis[i][p2]-1, ans);
        }printf("%d\n", ans);
    }
}
int main()
{
    init(); sol();
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值