Treasure Hunting(最短路 最大流)

原题: http://acm.hdu.edu.cn/showproblem.php?pid=3468

题意:

n* m的地图,上面有‘#’(不能走),‘.’(可以走),‘*’(宝藏)和字母。有两个人小A和小B,两人都会从地图A出发,小A会从A开始按顺序走到B,C…Z,a,b…z,一直走到最后一个单词为止,即如果只有ABC就走到C,如果只有ABD那么就不合法,每次都走最短路。小B也会按小A的速度走最短路(即同时到达下一个点),但是他可以走不同的路线,如果路线上有宝藏,他就会挖宝藏,但是从一个字母走到另一个字母的过程中他只能挖一个宝藏。

如果过程不合法请输出-1,如果合法,请输出小B最多可以获得多少个宝藏。

解析:

先排-1的情况有:

  1. 只有ABDE
  2. 出现AABC
  3. A走不到B

做一遍最短路。对于一个宝藏点p,第i个目标点 x i x_i ,如果 d i s ( p , x i ) + d i s ( p , x i + 1 ) = = d i s ( x i , x i + 1 ) dis(p,x_i)+dis(p,x_{i+1})==dis(x_i,x_{i+1}) ,则说明可以在 x i x_i x i + 1 x_{i+1} 的途中拿到。

建图:

  1. x i x_i x i + 1 x_{i+1} 这条路看成一个点 X i X_i ;宝藏点p因为只能被采一次,所以裂点 p 1 , p 2 p_1,p_2
  2. s p X i , X i p 1 , p 1 p 2 , p 2 e p sp\to X_i,X_i\to p_1,p_1\to p_2,p_2\to ep
#include<bits/stdc++.h>
using namespace std;
#define pill pair<int,int>
#define LL long long

const int inf = 0x3f3f3f3f;
const int N = 20500, M = 205000;

int head[N], nex[M], to[M], val[M], now;
void add(int a, int b, int v) {
    to[++now] = b;
    val[now] = v;
    nex[now] = head[a];
    head[a] = now;
    to[++now] = a;
    val[now] = 0;
    nex[now] = head[b];
    head[b] = now;
}

//*********************

int sp, ep, d[N];

int bfs() {
    queue<int>Q;
    memset(d, -1, sizeof(d));
    d[sp] = 0;
    Q.push(sp);
    while(!Q.empty()) {
        int p = Q.front();
        Q.pop();
        for(int i = head[p]; ~i; i = nex[i]) {
            int u = to[i];
            if(d[u] == -1 && val[i] > 0) {
                d[u] = d[p] + 1;
                Q.push(u);
            }
        }
    }
    return d[ep] != -1;
}

int dfs(int p, int v) {
    int r = 0;
    if(p == ep)
        return v;
    for(int i = head[p]; (~i) && r < v; i = nex[i]) {
        int u = to[i];
        if(val[i] > 0 && d[u] == d[p] + 1) {
            int x = dfs(u, min(val[i], v - r));
            r += x;
            val[i] -= x;
            val[i ^ 1] += x;
        }
    }
    if(!r)
        d[p] = -2;
    return r;
}

LL dinic() {
    LL ans = 0, t;
    while(bfs()) {
        while(t = (LL)dfs(sp, inf))
            ans += t;
    }
    return ans;
}

//***********************

void init() {
    now = -1; //要求第一条边为0
    memset(head, -1, sizeof(head));
}

const int di[4][2] = {{1, 0}, {0, 1}, {0, -1}, {-1, 0}};

char Mp[101][101];
int n, m;
int id(int x, int y) {
    return (x - 1) * m + y - 1;
}
pill pos[60];
int up;
int dis[60][10100];
bool vis[10100];

void get_dis() {
    for(int i = 1; i <= up; i++) {
        for(int j = 0; j <= id(n, m); j++) {
            dis[i][j] = inf;
        }
    }
    for(int i = 1; i <= up; i++) {
        memset(vis, 0, sizeof(vis));
        int x = pos[i].first, y = pos[i].second;

        queue<int> Q;
        dis[i][id(x, y)] = 0;
        Q.push(id(x, y));
        vis[id(x, y)] = 1;
        while(!Q.empty()) {
            x = Q.front() / m + 1, y = Q.front() % m + 1;
            Q.pop();
            for(int j = 0; j < 4; j++) {
                int xx = x + di[j][0], yy = y + di[j][1], Id = id(xx, yy);
                if(xx < 1 || yy < 1 || xx > n || yy > m || vis[Id] || Mp[xx][yy] == '#')
                    continue;
                if(dis[i][Id] > dis[i][id(x, y)] + 1) {
                    dis[i][Id] = dis[i][id(x, y)] + 1;
                    Q.push(Id);
                    vis[Id] = 1;
                }
            }
        }
    }
}

int Build() {
    for(int i = 1; i < up; i++) {
        int Id = id(pos[i].first, pos[i].second);
        add(sp, Id, 1);
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            if(Mp[i][j] != '*')
                continue;

            int Id = id(i, j);
            add(Id, Id + id(n, m) + 1, 1);
            add(Id + id(n, m) + 1, ep, 1);
            for(int k = 1; k < up; k++) {
                int id_k = id(pos[k].first, pos[k].second);
                int id_k1 = id(pos[k + 1].first, pos[k + 1].second);
                if(dis[k][id_k1] == inf)
                    return -1;
                if(dis[k][Id] + dis[k + 1][Id] == dis[k][id_k1])
                    add(id_k, Id, 1);
            }
        }
    }
}

int main() {
    while(cin >> n >> m) {
        sp = N - 2, ep = N - 1;
        init();

        for(int i = 1; i <= n; i++)
            scanf("%s", Mp[i] + 1);
        up = 0;
        int co = 0;
        memset(pos, 0, sizeof(pos));
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                if(Mp[i][j] == '*' || Mp[i][j] == '.' || Mp[i][j] == '#')
                    continue;
                co++;
                if(Mp[i][j] <= 'Z')
                    pos[Mp[i][j] - 'A' + 1] = {i, j}, up = max(up, Mp[i][j] - 'A' + 1);
                else
                    pos[Mp[i][j] - 'a' + 27] = {i, j}, up = max(up, Mp[i][j] - 'a' + 27);
                Mp[i][j] = '.';
            }
        }
        if(co != up) {
            printf("-1\n");
            continue;
        }
        bool f = 1;
        for(int i = 1; i <= up; i++) {
            if(pos[i].first == 0)
                f = 0;
        }
        if(!f) {
            printf("-1\n");
            continue;
        }

        get_dis();
        if(Build() == -1) {
            printf("-1\n");
            continue;
        }

        int ans = dinic();
        printf("%d\n", ans);
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/86656592