zoukankan      html  css  js  c++  java
  • 2019CCPC 秦皇岛 E.Escape

    传送门

    题意:
    给出一个(n*m)的迷宫,有(a)个入口,(b)个出口。
    现在有(a)个机器人都从入口出发,一开始方向默认为下,你可以选在在一些格子上面放置一个转向器,转向器有四种:

    • 向下走变为向右走;
    • 向下走变为向左走;
    • 向上走变为向右走;
    • 向上走变为向左走。

    每个格子最多放一个转向器。
    问最后是否存在一种方案,使得每个机器人都能到达从其中一个出口。

    思路:
    因为题目要求转向器只能接受固定方向,并且变为固定方向,所以有几个比较重要的观察:

    • 不存在两个机器人的路线共线;
    • 若一个格子上存在转向器,那么至多只能经过一个机器人;
    • 若一个格子上没有转向器,那么可以经过两个方向垂直的机器人。

    观察一挺好证明,若存在两个机器人共方向,说明其中一个机器人经过转向器,而另一个没有经过,出现矛盾。后面几个yy一下应该好理解。

    所以现在问题就是,一个格子只能横向经过或竖向经过,若经过转换器,只能经过一次,问能否使得(a)个机器人成功走到终点。

    考虑网络流,我们将点拆成两类:一类是“水平”类点,另一类是“垂直”类点。那么一开始我们有水平和水平的相连,垂直的和垂直的相连,流量为(1)
    考虑经过转换器时,方向发生了变化,那么我们对于一个点,允许其向另一个方向转化,流量为(1)
    容易发现这样的建图刚好符合上面的要求。

    PS:网上代码很多都是错的,因为没有考虑到障碍物的情况,注意一下最后到出口时,是否能到达((n,x))这个点。
    细节见代码:

    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    //#define Local
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 50005;
    
    #define INF 0x3f3f3f3f
    template <class T>
    struct Dinic{
        struct Edge{
            int v, next;
            T flow;
            Edge(){}
            Edge(int v, int next, T flow) : v(v), next(next), flow(flow) {}
        }e[N * 30];
        int head[N], tot;
        int dep[N];
        void init() {
            memset(head, -1, sizeof(head)); tot = 0;
        }
        void adde(int u, int v, T w, T rw = 0) {
            e[tot] = Edge(v, head[u], w);
            head[u] = tot++;
            e[tot] = Edge(u, head[v], rw);
            head[v] = tot++;
        }
        bool BFS(int _S, int _T) {
            memset(dep, 0, sizeof(dep));
            queue <int> q; q.push(_S); dep[_S] = 1;
            while(!q.empty()) {
                int u = q.front(); q.pop();
                for(int i = head[u]; ~i; i = e[i].next) {
                    int v = e[i].v;
                    if(!dep[v] && e[i].flow > 0) {
                        dep[v] = dep[u] + 1;
                        q.push(v);
                    }
                }
            }
            return dep[_T] != 0;
        }
        T dfs(int _S, int _T, T a) {
            T flow = 0, f;
            if(_S == _T || a == 0) return a;
            for(int i = head[_S]; ~i; i = e[i].next) {
                int v = e[i].v;
                if(dep[v] != dep[_S] + 1) continue;
                f = dfs(v, _T, min(a, e[i].flow));
                if(f) {
                    e[i].flow -= f;
                    e[i ^ 1].flow += f;
                    flow += f;
                    a -= f;
                    if(a == 0) break;
                }
            }
            if(!flow) dep[_S] = -1;
            return flow;
        }
        T dinic(int _S, int _T) {
            T max_flow = 0;
            while(BFS(_S, _T)) max_flow += dfs(_S, _T, INF);
            return max_flow;
        }
    };
    
    Dinic <int> solve;
    
    int n, m, a, b;
    char mp[105][105];
    
    int id(int x, int y) {
        return (x - 1) * m + y;
    }
    
    bool ok(int x, int y) {
        return x >= 1 && x <= n && y >= 1 && y <= m && mp[x][y] != '1';
    }
    
    void run() {
        solve.init();
    	cin >> n >> m >> a >> b;
    	int base = (n + 1) * m;
    	int s = 0, t = 2 * base + 1;
    	for(int i = 1; i <= n; i++) {
    		cin >> (mp[i] + 1);
    	}
        for(int i = 1; i <= a; i++) {
            int x; cin >> x;
            solve.adde(s, id(1, x), 1);
        }
        for(int i = 1; i <= b; i++) {
            int x; cin >> x;
            solve.adde(id(n, x), t, 1);
    }
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                if(mp[i][j] == '1') continue;
                if(ok(i - 1, j)) solve.adde(id(i, j), id(i - 1, j), 1);
                if(ok(i + 1, j)) solve.adde(id(i, j), id(i + 1, j), 1);
                if(ok(i, j - 1)) solve.adde(id(i, j) + base, id(i, j - 1) + base, 1);
                if(ok(i, j + 1)) solve.adde(id(i, j) + base, id(i, j + 1) + base, 1);
                solve.adde(id(i, j), id(i, j) + base, 1);
                solve.adde(id(i, j) + base, id(i, j), 1);
            }
        }
        if(solve.dinic(s, t) == a) cout << "Yes" << '
    ';
        else cout << "No" << '
    ';
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
    #ifdef Local
        freopen("../input.in", "r", stdin);
        freopen("../output.out", "w", stdout);
    #endif
        int T; cin >> T;
        while(T--) run();
        return 0;
    }
    

    较完整题解:hhh

  • 相关阅读:
    迭代器特性
    没有一代人的青春是容易的『白岩松,演讲』
    编程趣话
    重新给PPT排序
    打印长图
    罗永浩答网友问:“能跟我们分享一件印象深刻至今你都记得的牛逼么?”
    活成加菲这样真是绝了!加菲语录大搜罗!
    加菲猫经典语录收录
    那些难以忘记的加菲猫经典语录
    做好这5点基本要求 才能算一个合格的HTML5动画
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11671975.html
Copyright © 2011-2022 走看看