Codechef July Challenge 2019 Snake and Apple Tree

五迷三道 提交于 2019-12-01 08:54:57

 

费用流。
把每个方格拆成 $T$ 个点,$t$ 时刻一个方格向周围四个方格的 $t + 1$ 的点连一条容量为 $1$ 费用为 $0$ 的边,向自身的 $t + 1$ 连一条容量为 $1$ 费用为该方格最大幸福值的边。
源点向方格为 'S' 的0时刻连一条容量为 $1$ 费用为 $0$ 的边。所有点的 $T - 1$ 时刻向汇点连一条容量为 $1$ 费用为该方格最大幸福值的边。
还有每个格子同时刻不能有多条蛇呆在上面,再把每个点每个时刻拆成两个点,容量为 $1$ 费用为 $0$。跑最大费用最大流即可。

#include <bits/stdc++.h>
using namespace std;

const int N = 300;
const int NN = 1e5 + 7, M = 5e5 + 7;
const int INF = 0x3f3f3f3f;

template<class T>
inline void checkmax(T &a, T b) {
    if (a < b) a = b;
}
template<class T>
inline void checkmin(T &a, T b) {
    if (a > b) a = b;
}

struct E {
    int v, ne, f, c;
} e[M];
int head[NN], cnt, tol;
int id[N][N][85], mp[N][N][85];
int dis[NN], path[NN], n, m, z, t;
bool inq[NN];
char str[N][N];
const int dx[4] = {0, 1, 0, -1}, dy[4] = {-1, 0, 1, 0};

inline void add(int u, int v, int f, int c) {
    e[cnt].v = v; e[cnt].f = f; e[cnt].c = c; e[cnt].ne = head[u]; head[u] = cnt++;
    e[cnt].v = u; e[cnt].f = 0; e[cnt].c = -c; e[cnt].ne = head[v]; head[v] = cnt++;
}

bool spfa(int s, int t) {
    for (int i = 0; i <= t; i++)
        dis[i] = INF, inq[i] = 0, path[i] = -1;
    dis[s] = 0;
    inq[s] = 1;
    queue<int> que;
    que.push(s);
    while (!que.empty()) {
        int u = que.front(); que.pop();
        inq[u] = 0;
        for (int i = head[u]; ~i; i = e[i].ne) {
            int v = e[i].v, c = e[i].c;
            if (e[i].f && dis[v] > dis[u] + c) {
                dis[v] = dis[u] + c;
                path[v] = i;
                if (!inq[v]) {
                    inq[v] = 1;
                    que.push(v);
                }
            }
        }
    }
    return dis[t] != INF;
}

int mcf(int s, int t) {
    int ans = 0;
    while (spfa(s, t)) {
        for (int i = path[t]; ~i; i = path[e[i ^ 1].v]) e[i].f--, e[i ^ 1].f++;
        ans += dis[t];
    }
    return ans;
}

int main() {
    //freopen("in.txt", "r", stdin);
    memset(head, -1, sizeof(head));
    scanf("%d%d%d%d", &n, &m, &z, &t);
    for (int i = 1; i <= n; i++)
        scanf("%s", str[i] + 1);
    for (int i = 1; i <= z; i++) {
        int x, y, p, q, h;
        scanf("%d%d%d%d%d", &x, &y, &p, &q, &h);
        for (int j = p; j < q; j++)
            checkmax(mp[x][y][j], h);
    }
    tol = 1;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) if (str[i][j] != '#') 
            for (int k = 0; k < t; k++) {
                add(tol, tol + 1, 1, 0);
                //cout << tol << ' ' << tol + 1 << endl;
                id[i][j][k] = tol;
                tol += 2;
            }
    int S = tol + 1, T = tol + 2;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) if (id[i][j][0]) {
            for (int d = 0; d < 4; d++) if (id[i + dx[d]][j + dy[d]][0]) 
                for (int k = 0; k < t - 1; k++)
                    add(id[i][j][k] + 1, id[i + dx[d]][j + dy[d]][k + 1], 1, 0);
            for (int k = 0; k < t - 1; k++) 
                add(id[i][j][k] + 1, id[i][j][k + 1], 1, -mp[i][j][k]);
            add(id[i][j][t - 1] + 1, T, 1, -mp[i][j][t - 1]);
            if (str[i][j] == 'S') add(S, id[i][j][0], 1, 0);
        }
    printf("%d\n", -mcf(S, T));
    return 0;
}
View Code

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!