Codeforces Round #420 (Div. 2) D. Okabe and City 最短路

题目链接: Okabe and City

题目大意

n*m的地图, 有k个位置有路灯, (1, 1)位置保证一定有路灯, 人一开始的时候在(1, 1), 要走到(n, m), 并且人只能在有路灯的位置上走, 但可以花费一元钱让某一行或某一列亮起来, 注意在某个时刻只能有一行或一列被点亮, 也就是说, 你点亮一行或一列的时候, 上一次被点亮的那一行或一列就会熄灭, 所以人必须要站在一开始就被点亮的格子才能点亮其他行列, 问走到终点最小花费是多少, 不能走到终点输出-1

思路

最短
建图方法:
1. 相邻的有路灯的格子连边, cost = 0
2. 每一行每一列视作一个顶点, 有路灯格子与其相邻三行三列连边, cost = 1(从点亮的格子, 花费一元将附近某行某列点亮并走到那一行或列)
3. 有路灯格子相邻三行三列与这个格子连边, cost = 0(从点亮的行或列走到原先就有路灯的格子)
4. 如果终点(n, m)最初没有路灯, 将终点所在行与列与终点连边, cost = 0
然后用优先队列优化的Dijkstra

代码

#include <bits/stdc++.h>

using namespace std;
const int MAXN = 1E4 + 10, INF = 0x3f3f3f3f;
typedef pair<int, int> P;
struct edge
{
    int to, cost;
    edge(int a=0, int b=0) :to(a), cost(b) {}
};
vector<edge> G[MAXN*4];
int d[MAXN*4], dx[] = {0, 0, -1, 1, }, dy[] = {1, -1, 0, 0, }, n, m, k, r, c;
map<P, int> mp;

void dij(int s)
{
    priority_queue<P, vector<P>, greater<P>> que;
    fill(d, d+MAXN*4, INF);
    d[s] = 0;
    que.push(P(0, s));

    while(!que.empty())
    {
        P p = que.top(); que.pop();
        int v = p.second;
        if(d[v] < p.first) continue;
        for(int i=0; i<(int)G[v].size(); ++i)
        {
            edge e = G[v][i];
            if(d[e.to] > d[v] + e.cost)
            {
                d[e.to] = d[v] + e.cost;
                que.push(P(d[e.to], e.to));
            }
        }
    }
}

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    for(int i=0; i<k; ++i)
    {
        scanf("%d%d", &r, &c);
        for(int j=-1; j<=1; ++j)
        {
            G[i].push_back(edge(r+MAXN+j, 1));
            G[i].push_back(edge(c+2*MAXN+j, 1));
            G[r+MAXN+j].push_back(edge(i, 0));
            G[c+2*MAXN+j].push_back(edge(i, 0));
            mp[P(r, c)] = i;
        }
    }

    int x, y, nx, ny;
    for(auto &ite : mp)
    {
        x = ite.first.first; y = ite.first.second;
        for(int i=0; i<4; ++i)
        {
            nx = x + dx[i];
            ny = y + dy[i];
            if(mp.find(P(nx, ny)) != mp.end())
                G[mp[P(x, y)]].push_back(edge(mp[P(nx, ny)], 0));
        }
    }

    if(mp.find(P(n, m)) == mp.end())
    {
        G[n+MAXN].push_back(edge(k, 0));
        G[m+2*MAXN].push_back(edge(k, 0));
        mp[P(n, m)] = k;
    }

    dij(mp[P(1, 1)]);
    cout << (d[mp[P(n, m)]] == INF ? -1 : d[mp[P(n, m)]]) << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值