質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

1回答

1000閲覧

AtCoder 深さ優先探索がわかりません。

72234

総合スコア11

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2020/10/02 14:46

前提・実現したいこと

AtCoderの深さ優先探索の問題についての質問です。以下のような迷路を入力し、ゴールまで到達可能な場合Yes、そうでない場合Noを出力する問題です。エラーは起こらないのですが、ゴールに到達可能な場合にもNoが表示されてしまいます。どこに問題があるのか教えていただきたいです。

10 10 ...s...... #########. #.......#. #..####.#. ##....#.#. #####.#.#. ..#.#.#.#. #.#g#.#.#. #.#.#.#.#. #.....#...

該当のソースコード

C++

1#include <bits/stdc++.h> 2using namespace std; 3 4int main() { 5 6 int H,W,sx,sy,gx,gy,X,Y; 7 8 cin>>H>>W; 9 H--;W--; 10 char raby[H][W]; 11 bool rireki[H][W];//それぞれのマスが通過済みの場合はtrueを代入する 12 for(int i = 0; i<H+1; i++){ 13 for(int j = 0; j<W+1; j++){ 14 cin>>raby[i][j]; 15 rireki[i][j]=0; 16 if(raby[i][j]=='s'){sx=i; sy=j;}//スタートの位置 17 if(raby[i][j]=='g'){gx=i; gy=j;}//ゴールの位置 18 19 } 20 } 21 const int vx[4]={1,0,-1,0};//上下左右の移動用の配列 22 const int vy[4]={0,1,0,-1}; 23 24 rireki[sx][sy]=1; 25 stack<pair<int,int>> rec; 26 27 rec.push(make_pair(sx,sy)); 28 while(rec.empty()!=1){ 29 X=rec.top().first; 30 Y=rec.top().second; 31 rec.pop(); 32 33 for(int i = 0; i<4; i++){ 34 if(raby[X+vx[i]][Y+vy[i]]=='#'||rireki[X+vx[i]][Y+vy[i]]==1)continue; 35//行先が壁だったり通過済みの場合はスルー 36 if(X+vx[i]>=H||Y+vy[i]>=W||X+vx[i]<0||Y+vy[i]<0)continue; 37//場外の場合もスルー 38 if(raby[X+vx[i]][Y+vy[i]]=='.'||raby[X+vx[i]][Y+vy[i]]=='g'){ 39 rireki[X+vx[i]][Y+vy[i]]=1; 40 rec.push(make_pair(X+vx[i],Y+vy[i])); 41 } 42 43 } 44 } 45 46 if(rireki[gx][gy]==1)cout<<"Yes"<<endl; 47 if(rireki[gx][gy]==0)cout<<"No"<<endl; 48 for(int i = 0; i<H+1; i++){ 49 for(int j = 0; j<W+1; j++){ 50 cout<<rireki[i][j]; 51 } 52 } 53}

試したこと

それぞれのマスを通過したときにrirekiに1を入れるつもりだったのですが、試しにrirekiの値を出力してみたところ、通過可能なマスに正しく1が代入できていませんでした。上のテストケースだと、一番上の行の右側の角のところまでしか1が代入されていません。他の人のコードを参考にしてみたりもしましたが、どこに問題があるのかがわかりませんでした。拙い内容で恐縮ですが、何卒解答よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kuma_kuma_

2020/10/02 16:26

どちらかというと再帰関数の勉強だよね? でも質問者様のコードを見ると再帰関数になっていない... このまま完成させても再帰関数の勉強という意味では達成できていないことになる。 どうしたものか...
72234

2020/10/03 11:21

ご指摘ありがとうございます。 kuma_kuma様のおっしゃる通り、AtCoderでもメインの解説は再帰関数を用いています。 ただ、解説を見ずに取り組んだ際に、思いついた解法がスタックを用いたものであったため、 まずはこちらの方法で正解しておこうと思った次第です。 再帰関数を用いた方法もやってみようと思います。
guest

回答1

0

ベストアンサー

C++

1 H--;W--;

このコードは消し忘れですか? このデクリメントのせいで、縦H-1や横W-1を通るパスがすべて場外判定になってます。

C++

1 for(int i = 0; i<H+1; i++){ 2 for(int j = 0; j<W+1; j++){

このあたりのループも、このままでは範囲外のアクセスを起こします。もしかしたら上のデクリメントで減った分足してるのかもしれませんが、そもそもデクリメント必要ですか?

あと直接影響は出てないみたいですが、デクリメントしない場合でも下のコード

C++

1 if(raby[X+vx[i]][Y+vy[i]]=='#'||rireki[X+vx[i]][Y+vy[i]]==1)continue; 2//行先が壁だったり通過済みの場合はスルー 3 if(X+vx[i]>=H||Y+vy[i]>=W||X+vx[i]<0||Y+vy[i]<0)continue; 4//場外の場合もスルー

この評価順序は範囲外アクセスを起こします。

投稿2020/10/02 17:04

yudedako67

総合スコア2047

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

72234

2020/10/03 11:39

解答ありがとうございます。 デクリメントのところは、私が配列の要素数と添え字番号を混同したために起きたミスです。 ご指摘に沿って直したところ、解決することができました。 評価順序のところも自分では気づかなかったと思います。ご指摘ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問