大逃亡
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;
}