拯救公主

【题目描述】

有这样一张地图,地图上标记了勇者和公主分别所处的位置、一些无法踏入的禁区、一些传送门以及一些宝石,通过一个传送门能够瞬间转移到任意一个传送门,并且需要集齐K种宝石才能救出公主。

地图为一个R*C的字符矩阵,字符“S”表示勇者所处的位置,字符“E”表示公主所处的位置,字符“#”表示无法踏入的禁区,字符“$”表示传送门,字符“.”表示安全的位置,数字0~4表示宝石的种类。

勇者每次可以从当前位置到达其上下左右四个方向上的任意一个位置,但不能越过地图边界,勇者每走一步需要花费一个单位时间,从一个传送门瞬间转移到另一个传送门不需要花费额外时间,当勇者到达宝石所处的位置时,便视为得到了该宝石,不需要花费额外时间。

【输入描述】

第一行输入一个正整数T(1 <= T <= 10),表示共有T组数据;

每组数据输入格式如下:

第一行输入三个正整数R、C(2 <= R,C <= 200)、K,表示地图为一个R*C的矩阵,以及需要集齐K种宝石;

接下来R行,每行输入了C个字符,其含义如题中所述。

数据保证仅有一个“S”和“E”,“$”的数量不超过10个,宝石的类型在0~4的范围内。

【输出描述】

对于每组数据输出一行,每行包含一个数,表示勇者救出公主所花费的最少时间,如果勇者无法救出公主,输出“oop!”。

【样例输入】

1

7 8 2

........

..S..#0.

.##..1..

.0#.....

...1#...

...##E..

...1....

【样例输出】

11

源代码:

#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x44444444
using namespace std;
queue <int> Q;
int XDoor[10],YDoor[10],DP[201][201][1<<5];
int x[4]={1,0,-1,0};
int y[4]={0,1,0,-1};
char Map[201][201];
int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        int m,n,k,T1,T2,Num(0);
        memset(DP,0x44,sizeof(DP));
        scanf("%d%d%d",&n,&m,&k);
        for (int a=0;a<n;a++)
        {
            scanf("%s",Map[a]);
            for (int b=0;b<m;b++)
            {
                switch (Map[a][b])
                {
                    case '$':    XDoor[Num]=a;
                                YDoor[Num++]=b;
                                break;
                    case 'S':    Q.push(a);
                                Q.push(b);
                                Q.push(0);
                                DP[a][b][0]=0;
                                break;
                    case 'E':   T1=a;
                                T2=b;
                                break;
                    default :    break;
                }
            }
        }
        while (!Q.empty())
        {
            int t1=Q.front();
            Q.pop();
            int t2=Q.front();
            Q.pop();
            int t=Q.front();
            Q.pop();
            for (int a=0;a<4;a++)
            {
                int X=t1+x[a];
                int Y=t2+y[a];
                if (X<0||Y<0||X==n||Y==m||Map[X][Y]=='#')
                  continue;
                int T=DP[t1][t2][t]+1;
                int S=t;
                if ('0'<=Map[X][Y]&&Map[X][Y]<='4')
                  S|=1<<Map[X][Y]-'0';
                if (T>=DP[X][Y][S])
                  continue;
                if (Map[X][Y]=='$')
                  for (int b=0;b<Num;b++)
                  {
                    DP[XDoor[b]][YDoor[b]][S]=T;
                    Q.push(XDoor[b]);
                    Q.push(YDoor[b]);
                    Q.push(S);
                  }
                else
                {
                    DP[X][Y][S]=T;
                    if (Map[X][Y]=='E'&&S==(1<<k)-1)
                      continue;
                    Q.push(X);
                    Q.push(Y);
                    Q.push(S);
                }
            }
        }
        if (DP[T1][T2][(1<<k)-1]==INF)
          printf("oop!\n");
        else
          printf("%d\n",DP[T1][T2][(1<<k)-1]);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/Ackermann/p/5991053.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值