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

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

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

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

1回答

3722閲覧

動的計画法を用いて部分和問題を解きたいです。

RinT_hinabita39

総合スコア28

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2017/05/11 15:44

編集2017/05/11 15:46

###前提・実現したいこと
このページの問題を解きたいです。
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3886

概要は、いくつかの個数の整数を要素に持つ集合があり、その中から適当な整数を選び出して和をとると、指定した値にできるかどうかを判定するという問題です。集合の要素の個数、集合の要素の値、目標値は全て自分で指定します。

実行例は以下の通りです。

//Sample Input 4 // テストケース数 25 // 和を25にしたい 4 // 集合内にいくつの整数を要素として持つか 10 12 5 7 // 集合内の4つの整数要素を指定 925 // 和を925にしたい 10 // 集合の要素数は10 45 15 120 500 235 58 6 12 175 70 // 集合内の要素となる10個の整数 120 // 以下繰り返し 5 25 25 25 25 25 0 2 13 567 //Sample Output NO // その集合では和を25にできない YES // 和を925にできる NO YES

方針がわかりませんでしたが、いろいろ調べてみると以下のようなサイトを見つけたので、
ここに書いてある方針に倣い、動的計画法を使ってコードを書きました。
http://gushwell.ifdef.jp/etude/SubsetSum.html

###発生している問題・エラーメッセージ
コマンドプロンプト上で、上記のSample Input、並びにUDebug(https://www.udebug.com/UVa/12455)にある2つのInput例で試したところ、全く同じ結果が出力されました。
それにも関わらず、UVaでSubmitするとRuntime Errorとなってしまいます。

Runtime Errorについて調べたところ、「配列よりも大きな要素番号にアクセスしたり、ポインタの使用方法が間違っていたりして、セグメントエラーが発生することが主な原因」となるそうですが、もしそうだとしたら、コマンドプロンプト上で実行した時点で、結果が出力される前に何かしらのエラー文が出るのでは?と思いました。(自分はプログラミングができないので、十中八九この推測が違うんだろうとは思いますが)

せめてUVaが何行目でRuntime Errorとなったのか出してくれればいいのですが……
原因がまるで分らないので誰か助けてください……

###該当のソースコード

java

1import java.util.StringTokenizer; 2import java.io.*; 3 4class Bars { 5 public static void main (String[] args) { 6 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 7 8 try { 9 String line; 10 StringTokenizer token; 11 line = br.readLine(); 12 int testcase = Integer.parseInt(line); // テストケース数 13 14 for(int a=0; a<testcase; a++) { // テストケース数だけ一連の流れを繰り返す 15 line = br.readLine(); 16 int target = Integer.parseInt(line); // 目標値 和をこの値にできるかどうか 17 18 if(target==0) System.out.println("YES"); 19 // 目標値が0なら空集合を取れば和を0にできるのでYES 20 else { 21 line = br.readLine(); 22 int num = Integer.parseInt(line); // 集合の要素数 23 24 int tmp; 25 int ex = 0; // 目標値を超えた要素の値が来た時、ex(=exception)をインクリメント 26 int[] bar = new int[num]; // 要素数分の配列 27 line = br.readLine(); 28 token = new StringTokenizer(line, " "); 29 30 for(int i=0; i<num; i++) { 31 tmp = Integer.parseInt(token.nextToken()); 32 if(tmp<=target) bar[i-ex] = tmp; //要素が目標値より小さければ配列に入れる 33 else ex++; // そうでない場合は配列に入れずにexをインクリメント 34 } // 2行上でbar[i-ex]としているのは、例外が来ると要素数が減るため 35 36 num -= ex; // exの分だけ要素数が入力時よりも減る 37 38// この先は方針の参考にしたサイトに書いてある手順をコードにしました 39 int[] array = new int[target+1]; // 和が0~和がtarget → 大きさがtarget+1の配列 40 array[0] = 0; // 配列の先頭には0、あとは全て-1を入れて初期化 41 for(int i=1; i<=target; i++) array[i] = -1; 42 boolean judge = false; // 和がtargetになるとわかったらjudgeをtrueに書き換える 43 44 // nは参考サイトのnと同じ、jは同サイトにおけるi 45 for(int i=0; i<num; i++) { 46 int n = bar[i]; 47 48 for(int j=target; j>=0; j--) { 49 if(array[j]!=-1) { 50 if(n+j<=target && array[n+j]==-1) array[n+j] = n; 51 } 52 } 53 54 // array[target] (配列の最後)に-1以外が入った瞬間、それは和をtargetにできるということを意味する 55 if(array[target]!=-1) { 56 judge = true; 57 break; 58 } 59 } 60 61 if(judge) System.out.println("YES"); 62 else System.out.println("NO"); 63 } 64 } 65 66 } catch(IOException e) { 67 System.out.println("IOException" + e); 68 System.exit(1); 69 } 70 } 71} 72

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

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

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

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

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

guest

回答1

0

ベストアンサー

このコードでは目標数値が0である場合に、それに対応する集合要素の読み込みを行わず、
"Yes"を出力して次のテストケースを読み込むループに入ります。

この結果、その次の行の「集合の要素数」、さらに次の行の「集合の要素」を、
それぞれ次のループで「目標数値」、「集合の要素数」として読み込むことになります。
集合の要素としてスペース区切りとしている文字を要素数として変換しようとするため、
例外が発生してしまいます。

// 例として出ている入力において、最後のテストケースのあとにまだ続きがあったとしたら 0 //これがtargetに変換され、if(target==0)の判定でtrueになり、"Yes"を出力して次のループに移行 2 //次のループでこれがtargetに変換される 0ではないのでelseブロックへ 13 567 //集合の要素数numとしてこの文字列を変換しようとするが、変換できず例外発生

なので、目標数値が0でも、対応する要素数や集合の要素を全部ちゃんと読み込むようにする必要があります。

投稿2017/05/11 16:15

編集2017/05/11 16:58
swordone

総合スコア20651

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

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

RinT_hinabita39

2017/05/11 17:09

なるほど、Sample Inputの目標値が0のときに上手くいっていたのは、その後に何もなかったからですね… 無事Accepted頂きました!!本当にありがとうございます!!!!なんでそんなすぐ気付けるんですか…
swordone

2017/05/11 17:14

デバッグではコンパイルも通り、テストケースでは問題なく出力される、しかし本番ではRuntimeError。 つまり、何か特定の条件で例外が発生しているということになります。 しかもIOExceptionではcatchされてしまうので、例外はRuntimeException系ということになります。 このコードで起こり得るそれは配列絡みかInteger.parseIntくらいしかないので、そこに絞り込んで考えたまでです。
RinT_hinabita39

2017/05/11 17:46

なるほど、そういう論理立てになる訳ですね。まだプログラミングの経験と知識に乏しい自分にはなかなか厳しそうです… RuntimeException(実は初めて聞きました)やbinarySearchライブラリなど知らないこともいっぱい教えて下さり、それを自分で調べてみてへ~ってなってるので勉強の助けになってます。いつも本当にありがとうございます!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問