助けてください

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
168

助けてください

#1

投稿記事 by 168 » 4年前

10月からC言語を習い始め、学校で以下のような課題が出たのですが全くわかりません

問題
1から30までの範囲の乱数を5つ発生させる.ただし,発生させる乱数は必ず前の数よりも大きいものとし,それ以上大きいものが必要な数だけ出せなくなった場合には,それが判明した時点でストップさせるようにすること.

・最後まで表示できた場合の出力例
Random numbers: 2 10 17 24 26

・途中で打ち切られた場合の出力例
Random numbers: 25 28 -- Sorry! Impossible to print all.

特にわからないのは「発生させる乱数は必ず前の数よりも大きいものとする」ところと、どのように条件付けしてストップするのかです
どなたか回答・解説していただけると幸いです

アバター
夢幻ノ月夜
記事: 140
登録日時: 5年前
住所: Stens;Gate世界線

Re: 助けてください

#2

投稿記事 by 夢幻ノ月夜 » 4年前

俺も迷いましたが

乱数の範囲を「割った余り」の考え方で制御

直前に出した乱数が30だったらそこで打ち切り
違ったら乱数を出しなおす

これでいけないですかね?
毎回ゲーム作ろうとするたびに壁にぶち当たる

アバター
amehirune
記事: 181
登録日時: 6年前
住所: どっか
連絡を取る:

Re: 助けてください

#3

投稿記事 by amehirune » 4年前

以下のコードを見て、理解できたら教えてください。
尚、わざと汚く書いています(このまま提出したら怒られると思います)

コード:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

int main(){

	int num[5];

	srand((unsigned)time(NULL));

	num[0] = rand()%30+1;		printf("%2d ",num[0]);

	for(int i=1;i<5;){
	
		if( num[i-1]+i>=30 )	goto ERROR;
		num[i] = rand()%30+1;
		if( num[i-1] < num[i] ){
			printf("%2d ",num[i++]);
		}

	}
	return 0;

ERROR:
	printf("Sorry! Impossible to print all.\n");
	return 1;

}
理解してからきちんと書き直して提出することをお勧めします。
わからないことがあればちゃんと言ってください。時間がある限り教えますので^^
ほら、来いよ!! 誤字や矛盾を指摘したい奴から、前に出てこいよぉおおおおおおおッ!!!
※都合により、不定期でしか現れません。即返などはできませんのでご了承ください※

djann
記事: 27
登録日時: 7年前

Re: 助けてください

#4

投稿記事 by djann » 4年前

168 さんが書きました:それ以上大きいものが必要な数だけ出せなくなった場合には,それが判明した時点でストップさせるようにすること。
なので単に30だけではいけない。

例えば 29, 30 Sorry! Impossible to print all. という表示はNGで、29の時点でSorry! Impossible to print allを出さなければならない。
なぜならば、前回より大きい値を最後まで出し続けなければならないからです。それが途中で不可能になった時点で中断出力を行うのが、キモですね。


ちなみにプログラムは全体を一気に考えるのではなく、いくつかに分けて段階を踏んで考えていくと良いと思います。今回で言えば

A. まずは1から30の範囲で乱数を発生させるプログラム
B. 次は、Aで作ったプログラムを利用して、前回の値より大きい数字だけを表示させるプログラム
C. そして、途中で打ち切りSorry! Impossible to print allを表示させるプログラム

くらいに切り分けて進めていくといいと思いますよ。
参考に示されたコードが、果たしてそれぞれをどのように実装しているのか、それぞれのどの部分がどのコードに対応しているのかを見ながら読んでいくと、理解もしやすくなると思います。

かずま

Re: 助けてください

#5

投稿記事 by かずま » 4年前

そのまま提出できないような書き方ですが、参考になりますか?

コード:

#include <stdio.h>   // printf, putchar
#include <stdlib.h>  // srand, rand
#include <time.h>    // time
 
int main(void)
{
    int n, r, i;
    srand(time(0));
    for (r = i = 0, n = 30; i < 5 && n > i; i++, n = 30 - r)
        printf("%d ", r += rand() % n + 1);
    if (i < 5) printf("Sorry! Impossible to print all.");
    putchar('\n');
    return 0;
}
rand() の呼び出しは最大 5回です。

かずま

Re: 助けてください

#6

投稿記事 by かずま » 4年前

[quote="かずま" id=3,17317,134447]

コード:

    for (r = i = 0, n = 30; i < 5 && n > i; i++, n = 30 - r)
次のように訂正します。

コード:

    for (r = i = 0, n = 30; i < 5 && n >= 5 - i; i++, n = 30 - r)

boo123
記事: 2
登録日時: 4年前

Re: 助けてください

#7

投稿記事 by boo123 » 4年前

出来るだけわかりやすく書いてみました。
発生させる乱数値の下限をそれまで発生した乱数値+1としているのが特徴です。

コード:

#include <stdio.h> 
#include <stdlib.h>
#include <time.h>

int main( int argc, char **argv )
{
	int Min;		/* 乱数発生値の下限 */
	int Val;		/* 発生させた乱数値 */
	int i;

	/* 下限値初期化 */
	Min = 1;

	/* 乱数初期化 */
	srand(time(0));	

	/* 処理本体 */
	for ( i = 0; i < 5; i++ )
	{
		/* 下限値が30を超えたら「最後まで表示出来なかった」*/
		if ( Min > 30 )		
		{
			printf("Sorry! Impossible to print all.");	
			break;
		}

		/* 乱数発生 */
		Val = rand() % (30 - Min + 1) + Min;

		/* 下限値更新 */
		Min = Val + 1;

		/* 発生値表示 */
		printf("%d ", Val );
	}

	printf("\n");
	getchar();
}

アバター
asd
記事: 318
登録日時: 9年前

Re: 助けてください

#8

投稿記事 by asd » 4年前

他の方と被りますが手順としては、

1.30以下の乱数を発生させる
2.発生した乱数を下限値として保持しておく
3.下限値から判定して残りの個数分乱数が発生できない場合は打ち切る

となるかと思いますが、3の打ち切り判定がネックかなと思います。
168 さんが書きました: ・途中で打ち切られた場合の出力例
Random numbers: 25 28 -- Sorry! Impossible to print all.
上記の出力例を見ると二回目に28が出力されていて、まだ29、30が出力できるにも関わらず
打ち切られています。
これは乱数を5個発生させなければならないという条件から、2回目で28が出てしまうとあと3個乱数を発生させることができないために
打ち切る必要があるものと認識しています。

そのため30までの乱数を前回よりも必ず+1させた上で5個発生させる場合、
一番大きい値(しきい値)は以下の様になります。
1回目:26 2回目:27 3回目:28 4回目:29 5回目:30

上記の通り、1回目の乱数が26を超えた場合には残り4個の乱数を出力できないので
打ち切りとなります。
何回目の乱数を発生するのかをNにして一般化すると、N回目の乱数は30-(5-N)以下である必要があります。
(打ち切りの場合の出力例では1回目は25で1回目のしきい値以下なので継続、
2回目は28で2回目のしきい値を超えているので値の出力後打ち切るという流れと思います)

打ち切り判定をいつやるかとその判定内容がネックかと思います。
boo123 さんが書きました:出来るだけわかりやすく書いてみました。
発生させる乱数値の下限をそれまで発生した乱数値+1としているのが特徴です。
そのプログラムの場合、打ち切り出力例のように1回目が25、2回目が28だったとしても3回目の乱数が出力されてしまうと思います。
Advanced Supporting Developer
無理やりこじつけ(ぉ

boo123
記事: 2
登録日時: 4年前

Re: 助けてください

#9

投稿記事 by boo123 » 4年前

asd さんが書きました:他の方と被りますが手順としては、

打ち切り判定をいつやるかとその判定内容がネックかと思います。
boo123 さんが書きました:出来るだけわかりやすく書いてみました。
発生させる乱数値の下限をそれまで発生した乱数値+1としているのが特徴です。
そのプログラムの場合、打ち切り出力例のように1回目が25、2回目が28だったとしても3回目の乱数が出力されてしまうと思います。
なるほど仰るとおり打ち切り条件違ってますね。
御指摘いただき有り難うございます。
正しい打ち切り条件の場合、
if ( Min > 30 )

if ( Min > (26+i) )
に修正すると実現できます。
修正したソース下記です。

コード:

#include <stdio.h> 
#include <stdlib.h>
#include <time.h>

int main(int argc, char **argv)
{
	int Min;        /* 乱数発生値の下限 */
	int Val;        /* 発生させた乱数値 */
	int i;

	/* 下限値初期化 */
	Min = 1;

	/* 乱数初期化 */
	srand(time(0));

	/* 処理本体 */
	for (i = 0; i < 5; i++)
	{
		/* 最後の乱数発生で下限値が30を超えると予想される場合「最後まで表示出来なかった」*/
		if (Min > (26+i))
		{
			printf("Sorry! Impossible to print all.");
			break;
		}

		/* 乱数発生 */
		Val = rand() % (30 - Min + 1) + Min;

		/* 下限値更新 */
		Min = Val + 1;

		/* 発生値表示 */
		printf("%d ", Val);
	}

	printf("\n");
	getchar();
}

閉鎖

“C言語何でも質問掲示板” へ戻る