UESTC Training for Search Algorithm——G

大逃亡

Description

love8909遇到危险了!!!他被困在一个迷宫中,彷徨而无助。现在需要你来帮助他走出困境。他只能记住指定长度的指令(指令的长度由MinLen和MaxLen限定),并循环执行,而且他只会向下或向右(很奇怪吧^_^)。他在地图的左上角,你需要告诉他一个运动序列,即向下(D)或向右(R),使他能够成功走出这个图且不碰到陷阱。
如果还不明白,可以参看图片。图片1,2对应样例的第1组,图片3对应样例的第2组。

Input

第一行为1个整数T,表示有T组测试数据
第二行为4个整数Height, Width, MinLen, MaxLen,分别表示地图的高,宽,命令序列的最小和最大长度。3 <= Height, Width <= 60, 2 <= MinLen <= MaxLen <= 35
第三行至第Height+2行为地图信息。其中'.'表示空地,'X'表示陷阱。

Output

只有一行,为命令序列(只含D, R)。
注意:如果有多解,输入命令长度最短的;依然有多解,输出字典序最小的(D的字典序比R小),数据保证一定存在一组解。
字典序:字符串从前往后依次比较,第一个字符不同的位置,字符较小的字符串字典序较小,详情参见字典。

Sample Input

2
3 3 2 2
.X.
...
X..
5 5 2 3
..X.X
....X
.....
.XX..
XX..X

Sample Output

DR
DRR

Source

lcqbest

 

/*算法思想:
  我用DFS做的,先限制搜索指令的长度,然后再限制D,和R的长度,每一步要么是D
  要么是R,然后判断在这一步是不是可行,具体的方法就是依次判断是不是循环路径
  上每个点都能走,不是的话就返回false,并退出接下来的搜索,这样找到的第一个
  解就是最优解。
*/

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 100
using namespace std;
char ans[N];  //储存指令序列
char g[N][N];  //储存给的图
int height,width,minlen,maxlen;  //图的行数,列数,指令的最小长度,最大长度
int D,R;  //生成的指令中 D R 的个数
bool in(int x,int y)  //判断(x,y)是不是在矩阵中
{
    if(x>=0 && x<height && y>=0 && y<width) return true;
    else return false;
}
bool check(int x,int y)  //检查每个循环路径对应的点,是否可以走
{
    while(in(x,y))
    {
        if(g[x][y]=='X') return false;
        x+=D; y+=R;  //转换成下一个循环路径上的点
    }
    return true;
}
bool dfs(int x,int y,int left_D,int left_R)  //当前DFS到了(x,y)这个点,还剩下 left_D 个 D,left_R 个R
{
    if(!check(x,y)) return false;  //如果这个点不可走直接返回false,并退出
    if(left_D==0 && left_R==0)  //如果已经用完了所有的 D 和 R
    {
        ans[x+y]='\0';
        printf("%s\n",ans);  //找到了,返回true
        return true;
    }
    if(left_D>0)  //先枚举 D
    {
        ans[x+y]='D';
        if(dfs(x+1,y,left_D-1,left_R)) return true;
    }
    if(left_R>0)  //再枚举 R
    {
        ans[x+y]='R';
        if(dfs(x,y+1,left_D,left_R-1)) return true;
    }
    return false;  //没有找到,返回false
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d%d",&height,&width,&minlen,&maxlen);
        for(int i=0;i<height;i++)
            scanf("%s",g[i]);
        bool fg=false;  //判断是不是已经找到解了
        for(int i=minlen;!fg && i<=maxlen;i++)
            for(D=i;D>=0 && !fg;D--)  //先枚举D,把D尽可能的大
            {
                R=i-D;
                fg=dfs(0,0,D,R);
                if(fg) break;  //找到解了,不需要再往下搜下去
             }
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值