E - Escape Gym - 102361E

思路:每一个点分成四个方向,然后由于一个点可以转一个方向,设置一个中转站,入点和出点之间设置一个容量为1的边,要转弯就先进入这个中转站,再转入这个点的其他方向。

#include <bits/stdc++.h>

using namespace std;

const int maxn = 2e5;
const int maxm = 2 * maxn;
const int inf = 0x3f3f3f3f;

int n, m, S, T, in, ou;
char mp[110][110];
int h[maxn], tot, e[maxm], f[maxm], ne[maxm];
int q[maxn], d[maxn], cur[maxn];
int get(int x, int y)
{
    return (x - 1) * m + y;
}
void add(int u, int v)
{
    e[tot] = v; f[tot] = 1; ne[tot] = h[u]; h[u] = tot ++ ;
    e[tot] = u; f[tot] = 0; ne[tot] = h[v]; h[v] = tot ++ ;
}
bool bfs()
{
    int hh = 0, tt = -1;
    memset(d, -1, sizeof d);
    cur[S] = h[S];
    d[S] = 0;
    q[++tt] = S;
    while (hh <= tt)
    {
        int u = q[hh++];
        for (int i = h[u]; ~i; i = ne[i])
        {
            int v = e[i];
            if (f[i] && d[v] == -1)
            {
                d[v] = d[u] + 1;
                cur[v] = h[v];
                if (v == T) return  true;
                q[++tt] = v;
            }
        }
    }
    return false;
}
int dfs(int u, int limit)
{
    if (u == T) return limit;
    int flow = 0;
    for (int i = cur[u]; ~i && flow < limit; i = ne[i])
    {
        int v = e[i];
        if (d[v] == d[u] + 1 && f[i])
        {
            int t = dfs(v, min(f[i], limit - flow));
            if (!t) d[v] = -1;
            flow += t;
            f[i] -= t;
            f[i ^ 1] += t;
        }
    }
    return flow;
}
int dinic()
{
    int r = 0, flow;
    while (bfs()) {
        while (flow = dfs(S, inf))
            r += flow;
    }
    return r;
}

int main ()
{
    int cas;
    scanf("%d", &cas);
    while (cas--)
    {
        scanf("%d %d %d %d", &n, &m, &in, &ou);
        // printf("in=%d\n", in);
        for (int i = 1; i <= n; i ++ )
            scanf("%s", mp[i]+1);
        S = maxn - 2;
        T = maxn - 1;
        memset(h, -1, sizeof h);
        tot = 0;
        for (int i = 1; i <= n; i ++ )
        {
            for (int j = 1; j <= m; j ++ )
            {
                if (mp[i][j] == '1') continue;
                if (mp[i+1][j] == '0') add(0 * n * m + get(i, j), 0 * n * m + get(i+1, j));
                if (mp[i][j-1] == '0') add(1 * n * m + get(i, j), 1 * n * m + get(i, j-1));
                if (mp[i-1][j] == '0') add(2 * n * m + get(i, j), 2 * n * m + get(i-1, j));
                if (mp[i][j+1] == '0') add(3 * n * m + get(i, j), 3 * n * m + get(i, j+1));

                add(0 * n * m + get(i, j), 4 * n * m + get(i, j));
                add(1 * n * m + get(i, j), 4 * n * m + get(i, j));
                add(2 * n * m + get(i, j), 4 * n * m + get(i, j));
                add(3 * n * m + get(i, j), 4 * n * m + get(i, j));

                add(4 * n * m + get(i, j), 5 * n * m + get(i, j));

                add(5 * n * m + get(i, j), 0 * n * m + get(i, j));
                add(5 * n * m + get(i, j), 1 * n * m + get(i, j));
                add(5 * n * m + get(i, j), 2 * n * m + get(i, j));
                add(5 * n * m + get(i, j), 3 * n * m + get(i, j));
            }
        }
        for (int i = 0; i < in; i ++ )
        {
            int id;
            scanf("%d", &id);
            add(S, get(1, id));
        }
        for (int i = 0; i < ou; i ++ )
        {
            int id;
            scanf("%d", &id);
            add(get(n, id), T);
        }
        int mxflow = dinic();
        // printf("mxflow = %d in=%d\n", mxflow, in);
        if (mxflow >= in) puts("Yes");
        else puts("No");
    }
    return 0;
}
View Code

 

posted @ 2020-10-05 16:01  czwccc  阅读(113)  评论(0编辑  收藏  举报