D. Treasure Island | 搜索

题意:给你一个n x m的矩阵,其中’.‘可达,’#‘表示障碍。每次只能向右或者向下走,问至少添加多少个’#’,能够使得自(0, 0)走不到(n-1, m-1)。
一开始这题把我吓住了,觉得是不是要搞出所有可行的通路,然后找出重合的公共点,把这一点堵死。但其实不用这么麻烦,因为题目规定了移动方向只能是向下或者向右,所以答案只会是0,1,2三者其中之一。
但是想出这一点之后,还是存在问题,即使(0, 1)(1, 0)都为’.’,但由于地图不同,有可能他们最后都无法到达(n-1, m-1)。所以一直没想出该怎么取求。

赛后看题解,用两遍dfs,走过就标记’#’,这里也卡了好久。感觉自己还是基本功不扎实,对搜索理解的不透彻。我当时卡就卡在怎么记录这一路走过点的坐标,总不能用个vector,通过pair放进去,扫完了再统一标记吧?而且即使这样,因为dfs的过程中存在不可达通路,也没法判断哪些放进去哪些不放进去。
后来想到,暑假集训有个线段树+bfs的题,在每次递归之后加标记(把dfs设置成bool类型,如果返回1说明这是可行通路,那么在return的时候会一层层return回去,所以就一点点把走过的道路都加上了标记),于是就按照这个想法写。

虽然是对的,但是T在第16个样例。参考标程感觉想法是一样的,想不出为什么我就T了。研磨了半天发现了问题所在。

设置一个dfscnt变量,每次调用dfs都进行++,在程序的最后输出dfscnt。

4 5
. . . . .
. . . . #
. . . . .
. . #. .

以这组样例来讲,发现我的程序dfscnt = 22,标程dfscnt = 18。所以不难想象当测试的数据规模不断增大,和标程的效率差距也将体现的越来越明显。但是为什么会出现这种差异呢?
问题就出现在每次dfs调用加标记的地方,这是我的处理:如果dfs有结果,再沿途标记回来。

        dfs(tempx, tempy);
        if(ans)
        {
            matrix[tempx][tempy] = '#';
            return;
        }

这是标程的处理:不论dfs有没有结果,只要走到就标记为#。

        matrix[tempx][tempy] = '#';
        dfs(tempx, tempy);
        if(ans)    
            return;
#include <bits/stdc++.h>

using namespace std;

#define MAX_N 10010 //n, m
int n, m, ans, tempx, tempy, dfscnt;//n行m列表格
char c;
int step[2][2] = { {1, 0}, {0, 1} };
vector< vector<char> > matrix;

void dfs(int x, int y)
{
    dfscnt++;

    //printf("x %d  y %d  ans %d\n", x, y, ans);

    if(ans) return;

    if(x == n-1 && y == m-1)
    {
        ans++; return;
    }

    for(int i = 0;i < 2;i++)
    {
        tempx = x, tempy = y;
        tempx += step[i][0], tempy += step[i][1];

        //printf("i %d  tempx %d  tempy %d\n", i, tempx, tempy);

        if(tempx >= n || tempy >= m)
        {
            //printf("continue\n");
            continue;
        }

        if(matrix[tempx][tempy] == '#')
        {
            //printf("continue\n");
            continue;
        }
        //matrix[tempx][tempy] = '#';

         //printf("tempx %d tempy %d\n", tempx, tempy);

        matrix[tempx][tempy] = '#';
        dfs(tempx, tempy);
        if(ans)    return;
    }
    return;
}


int main()
{
    scanf("%d %d", &n, &m);//n行m列

    matrix.resize(n);//n*m

    for(int i = 0;i < n;i++)//行
    {
        matrix[i].resize(m);
        getchar();
        for(int j = 0;j < m;j++)//列
        {
            scanf("%c", &c);
            matrix[i][j] = c;
        }
    }

    ans = 0;
    dfs(0, 0);

    if(ans)
    {
        //printf("here\n");

        ans = 0;
        matrix[n-1][m-1] = '.';
        dfs(0, 0);

        if(ans)
            printf("2\n");

        else
            printf("1\n");
    }
    else
        printf("0\n");


    printf("dfscnt = %d\n", dfscnt);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值