Codeforces 821D(网格图缩列缩行+0-1BFS / 最短路)

Codeforces 821D
题意:题意:$n \times m$的地图,有$k$个位置是点亮的,有$4$个移动方向,每次可以移动到相邻的点亮位置,每次站在初始被点亮某个位置,暂时使某行或该某列全部点亮,花费为$1$,下一次使用时,上一次暂时点亮被熄灭.
问从$(1,1)$到$(n,m)$的最小花费

这题发现可以直接跑最短路。。每次循环找下一个灯如果相邻费用为0,如果能点亮一列过去费用为1,否则为INF,复杂度有点神奇

可以将行列缩成一个点,因为题目中点亮一次是一行或一列。然后每个灯可以连到周围能到的行列和灯,相应的边权看着办,然后边权只有01,跑0-1BFS。

2018.10.31 upd: 0-1 BFS 不要开vis数组!用dis松弛即可。

知识点
1、点拆了数组要开够大小
2、不要随便叉自己的想法!
3、map.find()用法

#include<cstdio> 
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<queue>
#include<climits>
#include<cmath>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
#define fir first
#define sec second
#define mp make_pair
using namespace std;
namespace flyinthesky {  
    const int MAXN = 10000 + 5, INF = 1000000000;

    struct lt {int r, c;} li[MAXN];
    struct edge {int u, v, w, nxt; } ed[10000005];

    int n, m, k, en, hd[MAXN * 3], dis[MAXN * 3];
    map<pair<int, int>, int > ma;
    deque<int > q;

    void ins(int x, int y, int w) {ed[++en] = (edge){x, y, w, hd[x]}, hd[x] = en;}
    void clean() {
        en = 0, ms(hd, -1);
    }
    int solve() { 
        scanf("%d%d%d", &n, &m, &k);
        clean();
        for (int i = 1; i <= k; ++i) scanf("%d%d", &li[i].r, &li[i].c), ma[make_pair(li[i].r, li[i].c)] = i;
        for (int i = 1; i <= k; ++i) {
            int x = li[i].r, y = li[i].c;

            ins(i, k + x, 1), ins(k + x, i, 0);
            if (x - 1 > 0) ins(i, k + x - 1, 1), ins(k + x - 1, i, 0);
            if (x + 1 <= n) ins(i, k + x + 1, 1), ins(k + x + 1, i, 0);

            ins(i, k + n + y, 1), ins(k + n + y, i, 0);
            if (y - 1 > 0) ins(i, k + n + y - 1, 1), ins(k + n + y - 1, i, 0);
            if (y + 1 <= m) ins(i, k + n + y + 1, 1), ins(k + n + y + 1, i, 0);

            int dx[4] = {1, 0, -1, 0};
            int dy[4] = {0, 1, 0, -1};
            for (int j = 0; j < 4; ++j) {
                int tx = dx[j] + x, ty = dy[j] + y;
                if (tx > 0 && ty > 0 && tx <= n && ty <= m) {
                    map<pair<int, int >, int >::iterator it = ma.find(make_pair(tx, ty));
                    if (it == ma.end()) continue ;
                    ins(i, it->second, 0), ins(it->second, i, 0);
                }
            }
        }
        for (int i = 0; i <= n + m + k; ++i) dis[i] = INF;
        dis[1] = 0, q.push_back(1);
        while (!q.empty()) {
            int u = q.front(); q.pop_front();
            for (int i = hd[u]; i > 0; i = ed[i].nxt) {
                edge &e = ed[i];
                if (dis[e.v] > dis[u] + e.w) {
                    dis[e.v] = dis[u] + e.w;
                    if (e.w == 0) q.push_front(e.v); else q.push_back(e.v);
                }
            }
        }
        int ans = min(dis[k + n], dis[k + n + m]);
        for (int i = 1; i <= k; ++i) if (li[i].r == n && li[i].c == m) ans = min(ans, dis[i]);
        if (ans == INF) cout << -1; else cout << ans;
        return 0; 
    }
}
int main() {
    flyinthesky::solve();
    return 0;
}
------ 本文结束 ------