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

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

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

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

Q&A

解決済

1回答

403閲覧

C++で競技プログラミング、main関数の書き方で標準入力が終了しない

hon.ki

総合スコア157

C++

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

0グッド

0クリップ

投稿2019/01/18 14:14

編集2019/01/18 14:18
//入力 int n, m, k[MAX_N] bool binary_search(int x) { //xの存在し得る範囲はk[l], k[l+1], ....k[r-1] int l = 0; r = n; //範囲に何も含まれなくなるませ繰り返す while (r - l >= 1) { int i = (l + r) / 2; if (k[i] == x) return true; //見つかった else if (k[i] < x) l = i + 1; else r = i; } //見つからなかった return false; } void solve() { sort(k, k + n); bool f = false; for (int a = 0; a < n; a++) { for (int b = 0; b < n; b++) { for (int c = 0; c < n; c++) { if (binary_search(m - k[a] - k[b] - k[c])) f = true; } } } } if (f) puts("Yes"); else puts("No"); } ```上記のコードは、プログラミングコンテストの参考書に載っていたもので、便宜的に入力が全てmain関数で読み込まれてグローバル変数に置かれたのち、関数solveが呼ばれることによって問題を解く形式で書かれています。 当の問題ですが、以下のようなものです。 <問題> あなたの友人は次のようなゲームをあなたに仕掛けてきました。数字が書かれたn舞の紙切れが袋に入っています。あなたはこの袋から紙切れを取り出し、数字を見て袋に戻すということを4回行い、4回の紙切れの数字を和がmになっていればあなたの勝ち、そうでなければ友人の勝ちになります。あなたはこのゲームに何度か挑戦しましたが、一度も勝つことができませんでした。怒ったあなたは袋を破り、滑れの紙切れを取り出して本当に勝つ可能性があるのかを調べることにしました。紙切れに書かれている数字がk1,k2,...knであったとき、和がmになる取り出し方が存在するかどうかを計算し、存在するならYes, 存在しないならNoと出力するプログラムを書きなさい。 <制約>1 <= n <= 50, 1 <= m <= 10**8(10の8乗), 1<= k_i <= 10**8(10の8乗) <例1> <入力>n = 3 m = 10 k = {1, 3, 5} <出力>Yes(例えば1,1,3,5のように出れば、和が10になる) <例2> <入力>n = 3 m = 9 a = {1, 3, 5} <出力>No(和が9になるような出方は存在しない) これを、ローカル環境で実行できる形に直そうとしたのが、以下のコードです。 ```ここに言語を入力 コード #include <cstdio> #include <algorithm> using namespace std; const int MAX_N = 50; int n, m, k[MAX_N]; //入力 bool binary_search(int x) { //xの存在し得る範囲はk[1], .... , k[r-1] int l = 0, r = n; //範囲に何も含まれなくなるまで繰り返す while (r - 1 >= 1) { int i = (1 + r) / 2; if (k[i] == x) return true; //見つかった else if (k[i] < x) l = i + 1; else r = i; } //見つからなかった return false; } void solve() { //二分探索をするためにソート sort(k, k + n); bool f = false; for (int a = 0; a < n; a++) { printf("a"); for (int b = 0; b < n; b++) { for (int c = 0; c < n; c++) { //もっとも内側のループの代わりに二分探索 if (binary_search(m - k[a] - k[b] - k[c])) { f = true; } } } } if (f) puts("Yes"); else puts("No"); } int main() { scanf("%d", &n); scanf("%d", &m); for (int i = 0; i < n; i++) { scanf("%d", &k[i]); } solve(); return 0; }

これを実行すると、指定の入力を与えても、入力待ち状態が終了しない状態が続いてしまいます。おそらく入力を受け取る処理を間違えているのだと思いますが、どう直せば良いのかどうしても分かりません。ご教授いただけますと幸いです。
どうぞよろしくお願いいたします。
なお、ローカル環境とは、mac OS High Sierra10.13.6
コンパイラは
Apple LLVM version 10.0.0 (clang-1000.10.44.4)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
になります。VSCodeを使っています。

また、蛇足ながら、エラーの再現を試みようと、

コード #include<cstdio> int main() { int k[10]; int n; scanf("%d", &n); for (int i = 0;i <n; i++) { scanf("%d", &k[n]); } for (int i = 0; i <n;i++) { printf("%d", k[i]); } return 0; }

というコードで、
4
1 2 3 4という入力に対して、
1234という出力を期待したのですが、出力されたのは0000でした。これは何故なのでしょうか。合わせてご教授いただけますと、幸いです。

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

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

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

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

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

guest

回答1

0

ベストアンサー

関数binary_search内において、
小文字のエル(l)を数字の一(1)に打ち間違えて居る箇所が二つあります。

C++

while (r - 1 >= 1) // ⇒ while (r - l >= 1)

C++

int i = (1 + r) / 2; // ⇒ int i = (l + r) / 2;


入力待ち状態が終了しない状態

正しくは、『入力を受け取った後、無限ループに突入』です。

デバッグ用に printf を埋め込むのは非常に良いアイデアなのですが、
効率化のためバッファリングが行われ、即時に出力されないことがあります。

検索しても、嵌っている人はそれなりにいるようです。Google検索 - printf バッファリング


エラーの再現を試みようと、... 出力されたのは0000でした。これは何故なのでしょうか。

凡ミスです。

C

1for (int i = 0;i <n; i++) 2{ 3 // 誤 scanf("%d", &k[n]); 4 scanf("%d", &k[i]); 5}

また、C++を使うのであれば、printf/scanf よりも cout/cin を使った方が良いように思います。
**修正:**実行時間の制約上、printf/scanf がより有効であるそうです。

投稿2019/01/18 14:30

編集2019/01/18 15:47
LouiS0616

総合スコア35660

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

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

REIK727

2019/01/18 15:29

重箱の隅をつつくようで申し訳ないですが、ひとつだけ補足させていただきます。 cout/cinはprintf/scanfよりも遅いので、競技プログラミングに限っては前者より後者が推奨されることが多いです(今回の問題は入力は最大でも50個強なのでどちらを使っても大差はないと思いますが、入力が1000個とか10000個とかある問題だと割と差が出ます)。
pepperleaf

2019/01/18 15:30

printf()でのデバッグは良く使いますが、最後に '\n' を入れないのはなぜ ? と思います。自分的には指が勝手に打っているのですが、、。
LouiS0616

2019/01/18 15:45

@REIK727 さん なるほど、そのような事情があるのですね。ご教示ありがとうございます。 @pepperleaf さん 私も改行文字は気付いたら入れてる派です。 ただ、ちょっとしたチェックだから改行せんでもいいやという感覚は何となく理解できる気もします。
pepperleaf

2019/01/19 01:05

改行文字は、入れないと次の入力と交錯(入れ替わる)する事があり、悩んだことから。もっとも入れすぎる事も多いですが。あとは、fflash()ですが、こちらは同一行で入力させたい場合のみ。
hon.ki

2019/01/19 01:16

LouiS0616さん、回答ありがとうございます。当該箇所を直したところ、無事プログラムは実行されました。エラー再現コードも、無事実行できました。また、printf()バッファリングのことは知りませんでしたので、大変参考になりました。また、REIK727さんも、補足していただいてありがとうございます。cout/cinよりprintf/scanfの方が速いということは、確かにそうですね。 また、pepperleafさん、改行文字の指摘をありがとうございます。確かに、そのほうが見やすいですね。参考になりました。 お三方とも、本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問