网易18实习生网测题--吃豆子

网易18实习生网测题–吃豆子

题目是酱滴,你是一个吃豆人,输入下面的参数,其中E表示没豆,W表示有豆。有三条规则:

4 5
EEWEW
EEWEE
EWEEE
EEEEW

  • 初始化的时候你在左上角,面向右边,而且保证这里没有豆(意思是不存在一个图只有左上角有豆这样不需要动你就赢了嘛)
  • 每一次你有两个移动选择,可以往面向的方向走一步
  • 也可以往下面走一步,但这样你面向的方向要反过来

最后问你吃完所有豆子的最短路径。图的最大格数是150*150。

DFS法

我们敲代码,就是一把梭。这不是要问最短路吗,BFS写起来麻烦,后面还有两道题呢。那我赶紧写一个DFS试试。

void dfs(int pn, int pm, int dir, int steps, int now)
{
    if(pn >=n || pm >= m)
    {
        return;
    }
    if(graphs[pn][pm] == 'W')
        now++;
    steps++;
    if(now >=target)
    {
        if(steps > answer)
            answer = steps;
        return;
    }

    if(dir ==0)
    {
        dfs(pn,pm-1,0,steps,now);
        dfs(pn+1,pm,1,steps,now);
    }
    else
    {
        dfs(pn,pm+1,1,steps,now);
        dfs(pn+1,pm,-1,steps,now);
    }
}

每次历遍一次,要不往当前方向走一步,然后dfs,要不下走一步,转向,继续dfs。结束条件是出了边界,或者吃完所有豆子了。登登登,一提交,过了50%样例,后面的超时了……

这就很懵了。我当时也没想到好的剪枝的方法。也没考虑一下复杂度。之后我找到有人说

通常DFS和BFS复杂度大约均为:系数*状态数^层数
通常此数最多为1亿就八成爆掉

哦,意思是大概是2^150嘛……得,老老实实找规律。

O(n)的解法

看起来比较简单哈,其实有一个模拟的思想在里面的。根据题意我们可以知道,其实吃豆子是有规律的,每次都必须吃完这一行的才能往下走,而且往下走的时候,还必须满足能吃完下面一行的要求。所以我用pm指示当前豆子位于的列位置,历遍所有行。依据以下步骤:
1. 如果这一行没有豆子,我们就直接跳下一行
2. 先把指针指到能保证吃完这一行的位置(如果面向左边,指针要走到这一行的最右边的豆子那里;如果面向右边,就要走到最左边的豆子那里。),计算需要步数。
3. 吃完这一行(就是如果是面左,就走到最左的豆子那里;反之亦然),计算步数。
4. 走下一行,转方向,重复1

额外情况是,如果都没有豆子,输出0就可以了,根本不用走。这是40%和50%case test夹着的那个test case的情况。

看起来比较清晰的步骤,其实自己做起来不够熟练,所以一些细节都不够周全,拖了很久,要练要练啊。其实考虑清楚这个清晰的步骤之后,写起来就很快了。

#include <iostream>
#include <cstdio>

using namespace std;

char graphs[150][150];
int target;
int n,m;
int l[150];
int r[150];
int main()
{
    //freopen("1.in","r",stdin);
    target = 0;
    cin >> n >> m;
    for(int i = 0; i < n; i++)
    {
        l[i]=r[i]=-1;
        bool isl = true;
        for(int j = 0; j < m; j++)
        {
            cin >> graphs[i][j];
            if(graphs[i][j] == 'W')
            {
                if(isl)
                {
                    l[i]=j;
                    isl=false;
                }
                r[i]=j;
                //cout<<l[i]<<r[i]<<endl;
                target++;
            }
        }
    }
    if(target == 0)
    {
        cout << 0 << endl;
        return 0;
    }
    int dire = 1;
    int ans = 0;
    int pm=0;
    bool flag =true;
    for(int i =0; i<n; i++)
    {
        if(l[i] < 0)
        {
            dire = -dire;
            continue;
        }

        if(flag)
        {
            ans += r[i]-pm;
            pm=r[i];
            flag = false;
            dire = -dire;
            continue;
        }
        if(dire > 0)
        {
            if(pm > l[i])
            {
                ans += pm - l[i] + r[i] - l[i];
                pm=r[i];
            }
            else
            {
                ans += r[i]-pm;
                pm=r[i];
            }
            dire = -dire;
        }
        else
        {
            if(pm < r[i])
            {
                ans += r[i]-pm + r[i]-l[i];
                pm=l[i];
            }
            else
            {
                ans += pm-l[i];
                pm=l[i];
            }
            dire = -dire;
        }
    }
    cout << ans+n-1 << endl;
    return 0;
}

登登,这样就肯定能过了,毕竟输入的复杂度都是O(n*m)了,所以必须能过啊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章