【DP】 ZOJ 3847 Collect Chars

4273 단어 dpZOJAC 로봇
먼저 모든 직렬에 AC자동기를 구축하여 dp[i][j][k]로 하여금 AC자동기에서 i보를 걷게 하고 j행, k열에 필요한 최소 걸음수에 이르게 한 다음에 spfa로 옮기면 된다...
#include <iostream>
#include <queue> 
#include <stack> 
#include <map> 
#include <set> 
#include <bitset> 
#include <cstdio> 
#include <algorithm> 
#include <cstring> 
#include <climits>
#include <cstdlib>
#include <cmath>
#include <time.h>
#define maxn 20025
#define maxm 4005
#define eps 1e-7
#define mod 1000000007
#define INF 0x3f3f3f3f
#define PI (acos(-1.0))
#define lowbit(x) (x&(-x))
#define mp make_pair
#define ls o<<1
#define rs o<<1 | 1
#define lson o<<1, L, mid 
#define rson o<<1 | 1, mid+1, R
#define pii pair<int, int>
#pragma comment(linker, "/STACK:16777216")
typedef long long LL;
typedef unsigned long long ULL;
//typedef int LL;
using namespace std;
LL qpow(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base;base=base*base;b/=2;}return res;}
LL powmod(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base%mod;base=base*base%mod;b/=2;}return res;}
// head

struct AC
{
	int next[maxn][26];
	int fail[maxn];
	bool end[maxn];
	char s[maxn];
	queue<int> q;
	int root, tail, now;

	int newnode()
	{
		end[tail] = 0;
		fail[tail] = -1;
		memset(next[tail], -1, sizeof next[tail]);
		return tail++;
	}

	void init()
	{
		tail = 0;
		root = newnode();
	}

	void insert()
	{
		scanf("%s", s);
		int len = strlen(s);
		now = root;
		for(int i = 0; i < len; i++) {
			int t = s[i] - 'A';
			if(next[now][t] == -1) next[now][t] = newnode();
			now = next[now][t];
		}
		end[now] = true;
	}

	void build()
	{
		now = root;
		for(int i = 0; i < 26; i++)
			if(next[now][i] == -1) next[now][i] = root;
			else {
				fail[next[now][i]] = root;
				q.push(next[now][i]);
			}
		while(!q.empty()) {
			now = q.front();
			q.pop();
			end[now] |= end[fail[now]];
			for(int i = 0; i < 26; i++)
				if(next[now][i] == -1) next[now][i] = next[fail[now]][i];
				else {
					fail[next[now][i]] = next[fail[now]][i];
					q.push(next[now][i]);
				}
		}
	}
};

struct node
{
	int si, sj, sk;
	node() {}
	node(int si, int sj, int sk) : si(si), sj(sj), sk(sk) {}
};

AC ac;
queue<node> q;
int dp[maxn][22][22];
bool in[maxn][22][22];
int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
char g[55][55];
int n, m, ans;

void spfa()
{
	while(!q.empty()) {
		int x = q.front().sj, y = q.front().sk, t = q.front().si;
		in[t][x][y] = false;
		q.pop();
		for(int i = 0; i < 4; i++) {
			int xx = x + dir[i][0], yy = y + dir[i][1];
			if(xx < 0 || yy < 0 || xx >= n || yy >= m) continue;
			if(g[xx][yy] == '#') continue;
			if(g[xx][yy] == '.') {
				if(dp[t][xx][yy] > dp[t][x][y] + 1) {
					dp[t][xx][yy] = dp[t][x][y] + 1;
					if(!in[t][xx][yy]) in[t][xx][yy] = true, q.push(node(t, xx, yy));
				}
			}
			else {
				int tt = g[xx][yy] - 'A';
				tt = ac.next[t][tt];
				if(dp[tt][xx][yy] > dp[t][x][y] + 1) {
					dp[tt][xx][yy] = dp[t][x][y] + 1;
					if(!in[tt][xx][yy]) in[tt][xx][yy] = true, q.push(node(tt, xx, yy));
				}
			}
		}
		if(g[x][y] != '.') {
			int tt = g[x][y] - 'A';
			tt = ac.next[t][tt];
			if(dp[tt][x][y] > dp[t][x][y]) {
				dp[tt][x][y] = dp[t][x][y];
				if(!in[tt][x][y]) in[tt][x][y] = true, q.push(node(tt, x, y));
			}
		}
	}
}

void read()
{
	scanf("%d%d", &n, &m);
	for(int i = 0; i < n; i++) scanf("%s", g[i]);
	int k;
	scanf("%d", &k);
	ac.init();
	for(int i = 0; i < k; i++) ac.insert();
	ac.build();
}

void work()
{
	memset(dp, INF, sizeof dp);
	memset(in, 0, sizeof in);
	int si = 0, sj = 0;
	for(int i = 0; i < n; i++)
		for(int j = 0; j < m; j++)
			if(g[i][j] == '@') si = i, sj = j, g[i][j] = '.';
	dp[0][si][sj] = 0;
	in[0][si][sj] = true;
	q.push(node(0, si, sj));
	ans = INF;
	spfa();
	for(int i = 1; i < ac.tail; i++)
		if(ac.end[i])
			for(int j = 0; j < n; j++)
				for(int k = 0; k < m; k++)
					ans = min(ans, dp[i][j][k]);
	printf("%d
", ans == INF ? -1 : ans); } int main() { int _; scanf("%d", &_); while(_--) { read(); work(); } return 0; }

좋은 웹페이지 즐겨찾기