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

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

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

アルゴリズム

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

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

配列

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

Q&A

解決済

2回答

1147閲覧

Atcoder過去問題、配列探索

schoolstudent

総合スコア5

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

アルゴリズム

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

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

配列

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

0グッド

0クリップ

投稿2021/07/14 12:41

編集2021/07/15 11:45

//解決しました!!!完成コード載せておきます。みなさん回答ありがとうございました。
今高校生なのですが、アルゴリズム検定に挑戦しようと思い過去問に取り組んでいました。
https://atcoder.jp/contests/past202010-open/tasks/past202010_c
↑こちらの問題について質問です。
自力でプログラミングを行ったところ、出力結果が一致しませんでした。

c言語

1// "%c"による文字列スキャン時の改行文字除外機能つき 2#include<stdio.h> 3int main(void){ 4 int i,j,tate,yoko,count[1000][1000]; 5 char c[1000][1000]; 6 scanf("%d",&tate); 7 scanf("%d",&yoko); 8 for(i=1;i<=tate;i++){ 9 for(j=1;j<=yoko;j++){ 10 scanf("%c",&c[i][j]); 11 if(c[i][j]=='\n'){ 12 j--; 13 } 14 } 15 } 16 for(i=1;i<=tate;i++){ 17 for(j=1;j<=yoko;j++){ 18 count[i][j]=0; 19 if(c[i][j]=='#'){ 20 count[i][j]++; 21 } 22 if(c[i][j+1]=='#'&&j+1!=yoko+1){ 23 count[i][j]++; 24 } 25 if(c[i][j-1]=='#'){ 26 count[i][j]++; 27 } 28 if(c[i+1][j]=='#'&&i+1!=tate+1){ 29 count[i][j]++; 30 } 31 if(c[i-1][j]=='#'&&i-1!=0){ //ここまでたてよこ 32 count[i][j]++; 33 } 34 if(c[i-1][j-1]=='#'&&i-1!=0&&j-1!=0){ 35 count[i][j]++; 36 } 37 if(c[i+1][j-1]=='#'&&i+1!=tate+1&&j-1!=0){ 38 count[i][j]++; 39 } 40 if(c[i+1][j+1]=='#'&&i+1!=tate+1&&j+1!=yoko+1){ 41 count[i][j]++; 42 } 43 if(c[i-1][j+1]=='#'&&i-1!=0&&j+1!=yoko+1){ 44 count[i][j]++; //ここまでななめ 45 } 46 printf("%d",count[i][j]); 47 } 48 printf("\n"); 49 } 50 return 0; 51}

これが作成したプログラムとなります。C言語で作成しました。
よろしければ、誤りを教えてくださるとうれしいです。

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

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

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

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

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

BeatStar

2021/07/14 12:56

コードは"<code>"または"<コード>"のボタンを押して出てくるやつの中に書きましょう。 インデントが無視されて読みづらいです。
schoolstudent

2021/07/14 13:03 編集

ご指摘ありがとうございます。今、修正いたしました。
jimbe

2021/07/14 13:10

c や count のアクセスする範囲の値が、ちゃんと想定したものになっていることを確認されていますか?
schoolstudent

2021/07/14 13:20

count[i][j]は数値変更は特にないのでアクセス範囲内に収まっています。 しかし、c[i][j]はアクセスしなくてもよいところにアクセスしているときもあります。ですが、'#'と一致する場合のみカウントするif文となっているため、それが結果に影響を及ぼすとは思っていないのですがどうなのでしょうか?そこも踏まえて教えて頂けるとうれしいです。
jimbe

2021/07/14 13:26

>それが結果に影響を及ぼすとは思っていない 結果が想定通りでないということは、思われている状態・動作では無いということではないでしょうか。 各値がどの段階で実際にどうなっているのかを確認もせず、大丈夫と思っているだけでは何も進みません。
schoolstudent

2021/07/14 13:46 編集

回答ありがとうございます。c[i][j]参照時、範囲外でも範囲内でも規則性なく数値が外れているので先ほどのような回答をしました。自分で解決するのが正しいことなのはわかります。ですが、今の時代C言語でこの形式の配列探索問題に対する解説は乏しく、検索してもヒットすることはありません。そういった問題の解決のためにこのサイトがあるのではないでしょうか?
jimbe

2021/07/14 14:00

念の為申し上げますが、何かを責めている訳ではありません。 プログラムを書いて動かした→思った結果にならない→考えても分からない、なら「大丈夫と思っている部分が実は何か違うのかもしれない」という視点でチェックしてはどうか…ということだけです。
jimbe

2021/07/14 16:26

ごめんさない、伝わり難い書き方をしてしまっていたことに気が付きました。 「c や count のアクセスする範囲の値」というのは、 c[i][j]/count[i][j] にアクセスした時の i や j の値の事では無く、 c[0~(tate+1)][0~(yoko+1)]/count[0~(tate+1)][0~(yoko+1)] の配列の中の値の事です。 失礼しました。
schoolstudent

2021/07/15 09:52

こちらも高圧的な態度で書き込みをしてしまい、申し訳ありませんでした。書き込みしてくださったところはしっかりと伝わっておりました。大丈夫です。昨日に引き続き同じ問題に取り組んでいるところです。
fana

2021/07/16 05:12

なんかもう終わってるみたいだけど… ・入力処理の結果が,自分が考えている通りのデータ状態になっているのか? ・配列やら何やらが自分が考えている通りのデータ状態になっているならば,処理部分はまともに動くのか? は,それぞれ独立して確認できるハズ. 「全体を通した処理結果が何かおかしいんだけど?」で立ち止まるのではなく, 「各処理部分のコードが自分が考えている通りに動いてるのか?」っていうことを真っ先に確認すべき. #「真っ先に」というのは「こういう場所に質問を投げる前に」だ.
guest

回答2

0

ベストアンサー

すでに他の方も指摘していますが、初期化していないローカル変数には、でたらめな値が入ります。
count0から始まらない、c#が紛れ込んで計数を誤るなどの問題が発生する可能性があります。

c

1 int i,j,tate,yoko,count[1000][1000]; 2 char c[1000][1000];

"%c"は改行も読み込むので、改行のぶんだけ全体の位置がずれてしまいます。

c

1 for(i=1;i<=tate;i++){ 2 for(j=1;j<=yoko;j++){ 3 scanf("%c",&c[i][j]); 4 } 5 }

printf("\n");をここに配置すると、出力の先頭で改行してしまいます。
各行の末尾で改行するようにしましょう。

c

1 for(i=1;i<=tate;i++){ 2 printf("\n");

たとえば、入力例1の場合、"%c"で読み込まれる最初の文字は、3 4の後ろにある改行文字です。
その後#.##が順番に読み込まれますが、その次に読み込まれるのはやはり改行文字です。
改行文字をnで表すと、最終的にcに読み込まれた結果は、以下のようになります。

text

1n#.# 2#n.. 3#.n#

これに対して#の数を数えると、以下の結果となります。

text

12221 23332 32211

最初の指摘を修正してもらえないようなので、何が起こっているかを説明しておきます。

c

1 int i,j,tate,yoko,count[1000][1000]; 2 char c[1000][1000];

こちらのコードは、ローカル変数のサイズを多くとっていることで、たまたまmain開始までに使われていない領域が割り当てられ、結果的に最初から0が設定されているように見えているだけです。

さて、ローカル変数に使用できるメモリには上限(環境によるが、linuxのgccで8MB)があります。上記のコードだと、countで4MB、cで1MBが使われます。今回は簡単なコードなので何とかなりましたが、ここからさらにintの配列が必要となったら、さらに4MB使うことになり破綻します。

問題によると、幅高さの最大値は30なので、それだけ確保した上で初期化して使うべきです。(先頭だけ値を指定すれば、残りは0で初期化されます)

c

1 int i,j,tate,yoko,count[32][32]={0}; 2 char c[32][32]={0};

もしくは、変数定義をmainの外に出してグローバル変数にするという手もあります。グローバル変数にはサイズ制限はほとんどありませんし、0で初期化されることが保証されています。

投稿2021/07/14 13:58

編集2021/07/18 01:10
actorbug

総合スコア2429

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

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

schoolstudent

2021/07/15 09:54

回答ありがとうございます。変数の初期化と改行位置変更しましたが、変化ありませんでした。"%c"は改行を含むというのはどういうことなのでしょうか?無知で申し訳ありませんが、プログラム動作的にどう改行されているのか教えてくださると嬉しいです。
actorbug

2021/07/15 10:39

回答に追記しました。
schoolstudent

2021/07/15 11:05

とっっっってもわかりやすい解説ありがとうございます!改行がスキャンされないように組み立ててみます!
schoolstudent

2021/07/15 11:41

ついにACできました; ; "%c"の特性ヒントのおかげです。 ありがとうございました; ;
guest

0

そもそも、countの中身が初期化されていないのでは?
あと、追記依頼コメントにもある通り、cの範囲外参照で意図せず#を余計に数えている可能性もあります。

投稿2021/07/14 13:32

swordone

総合スコア20669

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問