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

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

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

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

Q&A

1回答

2284閲覧

部分区間和の最大値を求めたいです。

Taka787

総合スコア23

C

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

0グッド

0クリップ

投稿2019/05/04 12:17

長文失礼いたします。

要件

整数値の列 d0, d1, ..., dn-1 (長さ n)に対して、その部分区間 dp, dp+1,..., dq-1 (0≦p≦q<n)の和の最大値を求めたいです。

入力:
標準入力から列の長さ n (0<n<10000000)が与えられる。
対象とする数値列の数値は、関数呼出し dataset(n); を行った後、関数呼出し nextdata() を行うと整数値 d0, d1, ..., dn-1 が次々と順に得られる。

※この関数呼出し nextdata() を n 回を超えて呼び出そうとするとプログラムの実行が打ち切られます。

出力:
この整数値の列 d0, d1, ..., dn-1 の部分区間 dp, dp+1,..., dq-1 (0≦p≦q<n)の和の最大値を書き出す。

※関数は別ファイルに定義してあります。

コード

c

1#include <stdio.h> 2#include <limits.h> 3 4#define MAX_CNT 1000 5 6 int getSum(int array[], int from, int to) { 7 int sum = 0, i; 8 for (i = from; i <= to; i++) { 9 sum += array[i]; 10 } 11 return sum; 12 } 13 14 void dataset(int n); 15 int nextdata(void); 16 17int main(int argc, char *argv[]){ 18 19 int n, z; 20 scanf("%d", &n); 21 dataset(n); 22 23 int answer = 0; 24 25 int array[9999999] = {0}; 26 27 for(z=0; z<=n-1; z++) { 28 array[z] = nextdata(); 29 } 30 31 int sum = 0, max = INT_MIN, from, to, j, i; 32 33 for (i = 0; i < MAX_CNT; i++) { 34 for (j = i; j < MAX_CNT; j++) { 35 sum = getSum(array, i, j); 36 if (max < sum) { 37 max = sum; 38 from = i; 39 to = j; 40 } 41 } 42 } 43 44 45for (i = from; i < to; i++) { 46 answer = answer + array[i]; 47} 48 49answer = answer + array[to]; 50 51printf("%d\n", answer); 52 53return 0; 54}

うまくいかない点

標準入力値が10000を超えると標準出力の値が正しい答えと異なった値が出力されます。

int型ではなくほかの型を使用する必要があるのでしょうか?
それともほかの場所が間違っているのでしょうか?
わかる方がいらっしゃいましたら、ご教授お願いいたします。

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

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

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

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

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

HogeAnimalLover

2019/05/04 12:27

dataset関数とnextdata関数の定義が見当たりません。宣言はありますけど。
jimbe

2019/05/05 00:05

部分区間の p と q はどういう値なのでしょうか. 「和の最大値」とはいったいなんでしょう.
guest

回答1

0

期待どおりの結果にならない原因

0<n<10000000

という条件にもかかわらず

#define MAX_CNT 1000

というなんだかよくわからない定数を用いてMAX_CNTの範囲の二重ループで最大値を求めようとしてますね。そこが根本的におかしい点だと思います。与えられたnだけが必要であり、MAX_CNTという定数を定義すること自体に意味が認められません。

いくつかの指摘

(1) 問題の内容にある部分数列の範囲は

dp, dp+1, ..., dq-1 (0≦p≦q<n)

ではなく

dp, dp+1, ..., dq (0≦p≦q<n)

だと思います。そうでないと入力データの最終要素dn-1はなんら結果に寄与しないので無意味となってしまいます。

(2) 質問者さんのプログラムの効率
質問者さんのアルゴリズムの計算量はO(N^3)だと思います。しかし問題の条件をよく考えればO(N)の計算量で結果が出ます。また配列arrayに入力データを全部覚える必要もありません。質問者さんのアルゴリズム(の方針)は正しい結果を出すこと自体はできるものの効率がよくないため例えばAtCoderのような「計算効率をも問う問題サイト」では正解とはみなされないと思います。
(追記: 上記の'^'はべき乗の意味です)

この問題は「最大部分配列 問題」という結構ポピュラーな問題で、効率のよい計算方法については「Kadane’s Algorithm」というキーワードで調べると出てくると思います。

(3) プログラムのスタイルなど
C言語のプログラムの書き方に気になる点がいくつかあります。アルゴリズムを考えるのも大事ですが「自分や他人が見てなるべくわかりやすいコードを書く」ことも大切ですので、その点も心がけましょう。

(A) 字下げ(インデンテーション)の仕方が変
(B) 変数スコープが無駄に長い

C

1int sum = 0, i; 2for (i = from; i <= to; i++) { 3 sum += array[i]; 4} 5return sum;

とすると変数iはfor文以降でもアクセスできるがその必要はない。ここは

C

1int sum = 0; 2for (int i = from; i <= to; i++) { 3 sum += array[i]; 4} 5return sum;

と書きたいところ。

(4) 追記:ローカル変数に巨大な配列を定義している
ローカル変数arrayですが、これほど巨大な大きさの配列をローカル変数として定義することは通常「よくない」と思います。どこまでならゆるされるかをはっきり言えないのですが自分ならせいぜい1000要素程度(数KB程度)が限度だと思っています。またローカル変数のバイト数がある程度以上大きな関数は再帰呼び出しを避けるといった注意も必要になるでしょう。大きな配列がどうしても必要ならグローバル変数とするか、mallocなどでヒープから動的に確保すべきだと思います。グローバル変数/mallocのどちらにすべきかはケースバイケースだと思います。

投稿2019/05/05 13:56

編集2019/05/05 14:12
KSwordOfHaste

総合スコア18394

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問