题解 P1189 【`SEARCH`】

本来以为是个大模拟,没想到自己被卡了好久…题解大佬都讲了剪枝,我自愧不如,但是个人认为本题除了剪枝这道题也有很多需要注意的细节,这篇题解我会一步一步讲自己的犯错经历,希望对你们有所帮助qwq

首先浏览一遍题意,感觉十分可做,大体思路是用dfs模拟每一次开车经历

ps:为了排版和方便阅读,只用向南作为例子,下同

pss:这篇题解不涉及剪枝内容

//v[x][y]用来记录车车的位置~
void dfs(int x,int y,int p){
    //位于x,y,正在处理第p条命令
    if(p>k)  return ;
    string heading=ord[p];
    if(heading=="SOUTH"){
        int fx=n-x;//对于点x,y,最多向下走n-x格
        for(int i=1;i<=fx;++i){
            int nx=x+i;//拓展出的点是nx,y
            if(a[nx][y]=='X')//如果碰到墙,说明往后走不了了
                return;
            v[x][y]=false;
            v[nx][y]=true;//车子从x,y开到了nx,y
            dfs(nx,y,p+1);//处理下一条命令
        }
    }
    ...//三个方向
}

//a[][]是地图
int main(){
    ...

    //输出答案
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            if(!v[i][j]){
                if(a[i][j]=='*')
                    putchar('.');
                else    putchar(a[i][j]);
            }
            else    putchar('*');
        }
        puts("");
    }
    return 0;
}

然后发现WA飞了hhhh(不考虑剪枝

仔细研究样例发现,对于每个命令,不可以不做(当然),也就是说,如果车在点x,y且准备向下走,而下方紧挨着墙,则说明这种情况不存在

我们愉快的加个特判w

if(heading=="SOUTH"){
    int fx=n-x;
    for(int i=1;i<=fx;++i){
        int nx=x+i;
        if(a[nx][y]=='X'){
            if(i==1)//走一步就是墙,说明车不可能在x,y
                v[x][y]=false;
            return;
        }
            v[x][y]=false;
            v[nx][y]=true;
            dfs(nx,y,p+1);
        }
    }
}

过了样例,感觉自己真的很不错,提交试试

…然后又WA飞了qwq

只能下大样例…下下来也没什么思路,左思右想觉得自己很对啊,于是手玩了几个数据

5 5
X....
..X.X
.*..X
..X.X
XXX.X
5
NORTH
EAST
SOUTH
WEST
NORTH

显然答案是

X*...
**X.X
....X
..X.X
XXX.X

而上面的代码跑出来了

X....
**X.X
....X
..X.X
XXX.X

嗯?

经过调试发现了上面代码的本质错误…

在一次搜索中,车开到了点x,y并将其赋值为true,但是在回溯后模拟其他情况时候,又将其改为了false

orz我笨死了…

也就是这里的问题

v[x][y]=false;
v[nx][y]=true;//车子从x,y开到了nx,y,但是如果我们之前的搜索证明了x,y本身可以抵达,回溯回来时候我们又把车开走了...
dfs(nx,y,p+1);//处理下一条命令

经过几分钟思考发现了一个结论: 当且仅当执行完所有命令后,车的位置才是有效的,其他时刻都是中间量

这不是显而易见吗

于是愉快的多加一个二维数组吧

if(heading=="SOUTH"){
    int fx=n-x;
    for(int i=1;i<=fx;++i){
        int nx=x+i;
        if(a[nx][y]=='X'){
            if(i==1)
                v[x][y]=false;
            return;
        }
        v[x][y]=false;
        v[nx][y]=true;
        if(p==k)
            fin[nx][y]=true;//只有在此时才是真正的可以到达
        dfs(nx,y,t+1);
    }
}

输出时候要按照fin的指导输出…

测了一下,终于A了滚粗…

然后回头看看代码,好像发现v数组没用上啊,开始的时候思路实在是错的彻底

精简一下代码

if(heading=="SOUTH"){
    int fx=n-x;
    for(int i=1;i<=fx;++i){
        int nx=x+i;
        if(a[nx][y]=='X') return;
        if(p==k)            fin[nx][y]=true;
        dfs(nx,y,t+1);
    }
}

原来这么简单啊

总结一下,遇到题先看清题意,手玩下样例,打代码之前先模拟orzz

由于版面问题,这里贴出完整的代码吧

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注