網易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)了,所以必須能過啊。

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