zoj 3847 Collect Chars(dp)

题目链接

Collect Chars

Time Limit: 2 Seconds      Memory Limit: 65536 KB

Bob was playing MC and was punished by Alice. Bob was trapped in a maze and there were some characters on some specific cells. When he walks on a specific point, he will pick up the character automatically (he cannot refuse to do that) and push back the character in his bag (You can treat it as adding a character to the end of a string and initially, the string is empty.). Alice has set several goal strings and when Bob's bag contains any one of the strings, Bob is enabled to return to the true world.

Bob can walk to the adjacent cell (up, down, left, right) at one time, and it costs no time to pick up the character and the character won't disappear, which means if Bob want's he can get endless characters once he walked on the certain cell but he must pick up at least one character.

Bob wants to leave the maze as soon as possible, and he asks you for the shortest time that he can go out of that maze.

Input

The first line is an integer n, indicating the number of testcases.

In each case, the first line is two integers L and C (0 < L, C ≤ 20). After this, L lines follow, and each has C characters. For each character, '.' stands for an open space, '#' stands for a wall which cannot be crossed, '@' stands for the beginning point of the maze. All capital letters 'A' to 'Z' stand for the characters which can be picked up.

After that, there is one integer W, which means the number of goal strings (0 < W ≤ 200). And W lines following, each line has a string, containing letters 'A' to 'Z' only, which length is less than 100.

Output

For each case, you should output an integer. The answer is the minimum time that Bob must use to get out of the maze. If he can't do that, you should output -1.

Sample Input
2
5 5
A.DB#
@#.##
.#..C
.#...
.....
3
AB
AC
BC
5 5
A.DB#
@#.##
.#..C
.#...
.....
2
AADBBBDCC
AC
Sample Output
11
9

题意:BOb在一个L*C的格子迷宫中,有些特别的格子里面有一个大写字母,每次Bob走到这个格子,至少要添加一个该字母到包里,相当于添加一个字母到字符串的末尾,初始的时候字符串为空。可以添加无数个(字母拿了不会消失,拿字母不花时间)。Alice有一些字符串,若有一个字符串为Bob包里的串的子串,Bob就可以走出迷宫。求Bpb走出迷宫的最小时间。

题解:枚举Alice的串,求出靠每个Alice的串走出迷宫的最小时间。对于每个串s,我们用dp[i][j][k] 表示当前在点(i,j),背包里的串的长度为j的后缀和s的长度为j的前缀相同,走到该状态的最短时间。用spfa的方法转移即可。代码如下:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<stdlib.h>
#include<vector>
#define inff 0x3fffffff
#define nn 110000
#define mod 1000000007
typedef long long LL;
const LL inf64=inff*(LL)inff;
using namespace std;
int c,l;
int w;
int dir[4][2]={1,0,-1,0,0,1,0,-1};
char tu[50][50];
LL dp[50][50][1100];
bool inque[50][50][1100];
struct node
{
    int x,y,zt;
    node(){}
    node(int xx,int yy,int zzt)
    {
        x=xx,y=yy,zt=zzt;
    }
}sta,tem;
queue<node>que;
void gengxin(int x,int y,int zt,int val)
{
    if(dp[sta.x][sta.y][sta.zt]+val<dp[x][y][zt])
    {
        dp[x][y][zt]=dp[sta.x][sta.y][sta.zt]+val;
        if(!inque[x][y][zt])
        {
            inque[x][y][zt]=true;
            que.push(node(x,y,zt));
        }
    }
}
LL solve(string s)
{
    int ls=s.size();
    int i,j,k;
    for(i=0;i<c;i++)
    {
        for(j=0;j<l;j++)
        {
            for(k=0;k<=ls;k++)
            {
                inque[i][j][k]=false;
                dp[i][j][k]=inf64;
            }
        }
    }
    while(que.size())
        que.pop();
    for(i=0;i<c;i++)
    {
        for(j=0;j<l;j++)
        {
            if(tu[i][j]=='@')
            {
                dp[i][j][0]=0;
                inque[i][j][0]=true;
                que.push(node(i,j,0));
            }
        }
    }
    int x,y;
    LL re=inf64;
    while(que.size())
    {
        sta=que.front();
        que.pop();
        inque[sta.x][sta.y][sta.zt]=false;
        if(sta.zt==ls)
        {
            re=min(re,dp[sta.x][sta.y][sta.zt]);
            continue;
        }
        if(tu[sta.x][sta.y]==s[sta.zt])
        {
            gengxin(sta.x,sta.y,sta.zt+1,0);
        }
        for(i=0;i<4;i++)
        {
            x=sta.x+dir[i][0];
            y=sta.y+dir[i][1];
            if(x>=0&&x<c&&y>=0&&y<l)
            {
                if(tu[x][y]==s[sta.zt])
                {
                    gengxin(x,y,sta.zt+1,1);
                }
                if(tu[x][y]=='@'||tu[x][y]=='.')
                {
                    gengxin(x,y,sta.zt,1);
                }
                if(tu[x][y]>='A'&&tu[x][y]<='Z'&&tu[x][y]!=s[sta.zt])
                {
                    gengxin(x,y,0,1);
                }
            }
        }
    }
    return re;
}
char sr[1100];
int main()
{
    int t,i;
    string s;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&c,&l);
        for(i=0;i<c;i++)
        {
            scanf("%s",tu[i]);
        }
        scanf("%d",&w);
        getchar();
        LL ans=inf64;
        for(i=1;i<=w;i++)
        {
            gets(sr);
            s=sr;
            ans=min(ans,solve(s));
        }
        if(ans==inf64)
            printf("%d\n",-1);
        else
            printf("%lld\n",ans);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值