zoj 3847 Collect Chars(ac自动机 + spfa)

来源:互联网 发布:颜艺MMD动作数据 编辑:程序博客网 时间:2024/05/16 14:19

题意:给一个地图, 地图上有一些字符, 每走到一个地方可以捡取若干个该字符,并且如果有字符的话最少要捡一个, 捡起来的字符放在一个队列里面,然后给一个字符串集合, 问最少要走多少步才能使队列里面最少存在一个给定的字符串。

搞法:

由于不是所有拾取的字符串达到要求,而是有一截满足条件就行, 那么就可以先把字符串集合构成ac自动机, 然后在自动机上跳转状态。

dp[i][j][k] 表示在ac自动机的第i个节点, 地图上的j行k列的最少花费,由于在一个有字符的地方可以有两个选择, 就是跳到下一个位置或者再原地停留, 继续拾取当前的字符, 所以转移就有0和1两种代价, 所以写成最短路形式的dp。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <string>#include <cmath>#include <queue>#include <stack>#include <set>#include <map>#include <cstdlib>using namespace std;#define LL long long#define inf 0x3f3f3f3f#define eps 1e-8#define ULL unsigned long long#define mnx 420#define mxe 10020#define mxnode 20020#define mod 1000000007char g[22][22];int n, m, cnt;char s[mnx];int dp[20020][22][22];int sx, sy;int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};bool in(int x, int y) {return x >= 1 && y >= 1 && x <= n && y <= m;}bool inq[20020][22][22];struct trie {    int ch[mxnode][26];    bool mark[mxnode];    int f[mxnode], sz;    int creat() {        memset(ch[sz], -1, sizeof(ch[sz]));        mark[sz] = 0;        return sz++;    }    void init() {        sz = 0, creat();    }    void insert(char *s) {        int t = 0;        for(int i = 0; s[i]; ++i) {            int c = s[i] - 'A';            if(!~ch[t][c]) ch[t][c] = creat();            t = ch[t][c];        }        mark[t] = 1;    }    void build() {        queue<int> q; f[0] = 0;        for(int i = 0; i < 26; ++i) {            int &v = ch[0][i];            if(!~v) v = 0;            else f[v] = 0, q.push(v);        }        while(!q.empty()) {            int t = q.front(); q.pop();            if(mark[f[t]]) mark[t] = 1; //注意要不要加这行            for(int i = 0; i < 26; ++i) {                int &v = ch[t][i];                if(!~v) v = ch[f[t]][i];                else {                    f[v] = ch[f[t]][i];                    q.push(v);                }            }        }    }    int spfa() {int ret = inf;memset(inq, 0, sizeof inq);memset(dp, 0x3f, sizeof dp);dp[0][sx][sy] = 0;queue<int> q;q.push(0), q.push(sx), q.push(sy);while(!q.empty()) {int s = q.front(); q.pop();int x = q.front(); q.pop();int y = q.front(); q.pop();inq[s][x][y] = 0;for(int i = 0; i < 4; ++i) {int dx = x + dir[i][0];int dy = y + dir[i][1];if(!in(dx, dy)) continue;if(g[dx][dy] == '#') continue;if(g[dx][dy] == '.') {if(dp[s][dx][dy] <= dp[s][x][y] + 1) continue;dp[s][dx][dy] = dp[s][x][y] + 1;if(!inq[s][dx][dy])inq[s][dx][dy] = 1, q.push(s), q.push(dx), q.push(dy);continue;}int t = ch[s][g[dx][dy]-'A'];if(dp[t][dx][dy] <= dp[s][x][y] + 1) continue;dp[t][dx][dy] = dp[s][x][y] + 1;if(!inq[t][dx][dy])inq[t][dx][dy] = 1, q.push(t), q.push(dx), q.push(dy);}if(g[x][y] != '.') {int t = ch[s][g[x][y]-'A'];if(dp[t][x][y] > dp[s][x][y]) {dp[t][x][y] = dp[s][x][y];if(!inq[t][x][y])inq[t][x][y] = 1, q.push(t), q.push(x), q.push(y);}}}for(int i = 1; i < sz; ++i) {if(mark[i] == 0) continue;for(int j = 1; j <= n; ++j)for(int k = 1; k <= m; ++k)ret = min(ret, dp[i][j][k]);}if(ret == inf) ret = -1;return ret;    }}ac;int main() {int cas;scanf("%d", &cas);while(cas--) {scanf("%d%d", &n, &m);for(int i = 1; i <= n; ++i)scanf("%s", g[i] + 1);for(int i = 1; i <= n; ++i)for(int j = 1; j <= m; ++j)if(g[i][j] == '@') {sx = i, sy = j, g[i][j] = '.';break;}ac.init();int q;scanf("%d", &q);while(q--) {scanf("%s", s);ac.insert(s);}ac.build();printf("%d\n", ac.spfa());}return 0;}


0 0
原创粉丝点击