ふりわけプログラム

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

ふりわけプログラム

#1

投稿記事 by デデ » 9年前

はじめて投稿します。C言語について完全に初心者なのでよろしくお願いします。
説明が下手で伝わりにくかったらすみません。

ひとつの値Xを5つに分類しようとしています。
5つをa,b,c,d,eとすると、それぞれの割合を0.3,0.4,0,1,0.1,0.1とします。(合計が1)
X=6とすると、それらをかけてa=1.8,b=2.4,c=0.6,d=0.6,e=0.6となります。
しかし、a,b,c,d,eは整数なので、まず1の位だけを見て、すべてを合計するとa=1,b=2,c,d,e=0となります。
これでは、a~eの合計が3なので、これを6にするにはあと3必要です。
そのため,小数第一位だけをみて大きい順に1プラスしていきます。
まず、aを1プラスします。残りが2つでa~eをみるとc,d,eが同じ値なのでこの中から2つを
1プラスします。この選び方はランダムとします。今回はdとeをプラスすることにします。

結果としてふりわけられた値は
a=2,b=2,c=0,d=1,e=1 となります。

Xの値はtextBoxで入力し、割合は決まっているものとし、
振り分け結果が出力されるようなプログラムがつくりたいです。

C++を使っています。どのようなプラグラムを作ればこのようなことができるのか教えてほしいです。
よろしくお願いします。

non
記事: 1097
登録日時: 9年前

Re: ふりわけプログラム

#2

投稿記事 by non » 9年前

割合が、小数点以下1桁だと限定すれば、
3:4:1:1:1と考えることができます。Xが整数なら、(たとえば6なら)
18:24:6:6:6ですね。したがって10で割った商は
1:2:0:0:0となり、10で割った時の余りは
8:4:6:6:6です。この余りが大きいほうから割り振ればいいと思います。

小数点以下1桁だと限定できないなら、浮動小数点で考慮しなくてはいけないので、
小数点以下だけを取り出し、ソートする方法があります。
non

デデ

Re: ふりわけプログラム

#3

投稿記事 by デデ » 9年前

返信ありがとうございます。
頭では理解できるんですけど、いざプログラムにしようとすると難しいです。

できればサンプルでも良いのでプログラムを教えて頂けないでしょうか。

アバター
Tatu
記事: 445
登録日時: 9年前
住所: 北海道

Re: ふりわけプログラム

#4

投稿記事 by Tatu » 9年前

プログラムにするのが難しいとのことですが
今の時点ではどれが書けますか?

1.xの値を代入させる
2.xに割合をかけた値a,b,c,d,eを求める
3.a,b,c,d,eの整数部分を出し、余りを求める
4.a,b,c,d,eの小数点以下を出す
5.a,b,c,d,eの小数点以下のうち最大のものはどれかを求め、
その整数部分に1をたす。
6. 余りがなくなるまで5をループさせる
7.結果表示

デデ

Re: ふりわけプログラム

#5

投稿記事 by デデ » 9年前

すみません。昨日からやりだしたんで、まだ2までしかできません。

アバター
bitter_fox
記事: 607
登録日時: 9年前
住所: 大阪府

Re: ふりわけプログラム

#6

投稿記事 by bitter_fox » 9年前

横からで申し訳ないですが、以下nonさんが提示したアルゴリズムのサンプルプログラムです。

コード:


//3:4:1:1:1と考えることができます。Xが整数なら、(たとえば6なら)
//18:24:6:6:6ですね。 (Mr.non's algorism)

void test() // programmed by bitter_fox
{
    int counter;
    int raito[5] = {3, 4, 1, 1, 1};
    int X = 6;

    for (counter = 0; counter < 5; counter++)
    {
        raito[counter] *= X;
    }
}

コード:


//18:24:6:6:6ですね。
//したがって10で割った商は1:2:0:0:0となり (Mr.non's algorism)

void test() // programmed by bitter_fox
{
    int counter;
    int raito[5] = {18/10, 24/10, 6/10, 6/10, 6/10};
    int now = 0;

    for (counter = 0; counter < 5; counter++)
    {
        now += raito[counter];
    }
}

コード:


//10で割った時の余りは8:4:6:6:6です。
//この余りが大きいほうから割り振ればいいと思います。 (Mr.non's algorism)

void test() // programmed by bitter_fox
{
    int counter, counterY;
    int raito[5] = {18%10, 24%10, 6%10, 6%10, 6%10};
    int buf_raito[5] = {18%10, 24%10, 6%10, 6%10, 6%10};
    int random[5] = {3, 4, 0, 2, 1}; // この値を添え字に使うことでランダム性を作る。当然実際の値は、実行時にランダムに作る
    int X = 6;
    int now = 3;
	int temp;

    for (counter = 0; counter < 5; counter++)
    {
        for (counterY = 5-1; counterY > counter; counterY--)
        {
            if (buf_raito[counter] < buf_raito[counterY])
            {
                temp = buf_raito[counter];
                buf_raito[counter] = buf_raito[counterY];
                buf_raito[counterY] = temp;
            }
        }
    }

    for (counter = 0; counter < X - now; counter++)
    {
        buf_raito[counter%5] += 10;
    }

    for (counter = 0; counter < 5; counter++)
    {
        for (counterY = 0; counterY < 5; counterY++)
        {
            if (raito[random[counter]] == buf_raito[counterY]%10) // 同じ余りのものがあったら
            {
                raito[random[counter]] += (buf_raito[counterY]/10)*10;
            	buf_raito[counterY] = 0; // リストからはじく。
                break; // 見つかったので、後ろの検索をせずに飛び降りる
            }
        }
    }
}
あくまでサンプルです。それぞれサンプルをコピペでつなげるだけでは、本来の動作をしません。(というより、もしかしたらこっちから答えを見つけるほうが難しいかも??)
あと「この選び方はランダムとします」ということなので、そのことも考慮しました。

[hr]
修正(algolism ==> algorism)

アバター
Tatu
記事: 445
登録日時: 9年前
住所: 北海道

Re: ふりわけプログラム

#7

投稿記事 by Tatu » 9年前

C言語について完全に初心者と書いていたので
配列を使わないものを考えていたのですが、
余りをランダムに振り分ける場合があることを考えると
配列を使った方がよいですね。

bitter_foxさんのサンプルのうち
3つめで得られるraitoはprintfなどで表示させるようにすればわかりますが
答えそのものではありません。

3.について
もし、小数をそのまま扱いたい場合は
y=(int)x;
とすることで小数xの整数部分をyに代入できます。

デデ

Re: ふりわけプログラム

#8

投稿記事 by デデ » 9年前

みなさん返信ありがとうございます。丁寧に教えていただいて本当にうれしいです。
まだまだ勉強不足だと思いました。 いろいろ勉強して、教えてもらったことを参考に頑張りたいと思います。

アバター
bitter_fox
記事: 607
登録日時: 9年前
住所: 大阪府

Re: ふりわけプログラム

#9

投稿記事 by bitter_fox » 9年前

Tatu さんが書きました: bitter_foxさんのサンプルのうち
3つめで得られるraitoはprintfなどで表示させるようにすればわかりますが
答えそのものではありません。
ですね。

raito[5]の宣言時に、%10している所為ですね。
本当は、raito[5]には{18, 24, 6, 6, 6}が入っているのでその状態が維持されているようにサンプルを作るべきでしたね。。

修正版です。以下では、適切な答えが出るはずです。

コード:

///////////////////////////////////////////////////////////////////////////
// 修正版
///////////////////////////////////////////////////////////////////////////

//10で割った時の余りは8:4:6:6:6です。
//この余りが大きいほうから割り振ればいいと思います。 (Mr.non's algorism)
 
void test() // programmed by bitter_fox
{
    int counter, counterY;
    int raito[5] = {18, 24, 6, 6, 6}; // 修正点(この時点では、この状態が維持されていなければならない)
    int buf_raito[5] = {18%10, 24%10, 6%10, 6%10, 6%10};
    int random[5] = {3, 4, 0, 2, 1}; // この値を添え字に使うことでランダム性を作る。当然実際の値は、実行時にランダムに作る
    int X = 6;
    int now = 3;
    int temp;
 
    // ソートする(バブルソート)(降順)
    for (counter = 0; counter < 5; counter++)
    {
        for (counterY = 5-1; counterY > counter; counterY--)
        {
            if (buf_raito[counter] < buf_raito[counterY]) // より大きいのが見つかったら
            {
                temp = buf_raito[counter];                      // 入れ替える
                buf_raito[counter] = buf_raito[counterY];
                buf_raito[counterY] = temp;
            }
        }
    }
 
    // 足りない分だけ1(ここではすべての値を10倍しているので10)足していく
    for (counter = 0; counter < X - now; counter++)
    {
        buf_raito[counter%5] += 10; // もしカウンターが5以上になると配列の外を参照するので %5 で巡回
    }
 
    for (counter = 0; counter < 5; counter++)
    {
        for (counterY = 0; counterY < 5; counterY++)
        {
            // 修正点(raito[random[counter]]のほうも10の剰余を求めるようにする)
            if (raito[random[counter]]%10 == buf_raito[counterY]%10) // 同じ余りのものがあったら
            {
                raito[random[counter]] += (buf_raito[counterY]/10)*10;
                buf_raito[counterY] = 0; // リストからはじく。
                break; // 見つかったので、後ろの検索をせずに飛び降りる
            }
        }
    }

    // 以下追記(出力できるように)
    for (counter = 0; counter < 5; counter++)
    {
        printf("%d, ", raito[counter]/10);
    }
    printf("\b\b \n"); // 最後の余分なコンマを削除
}
Tatuさん御指摘ありがとうございました。

[hr]
追記:ソース内のコメントを増やしました。

フリオ

Re: ふりわけプログラム

#10

投稿記事 by フリオ » 9年前

 質問の条件をそのままコードにしました。
いちいち最大値を探すので効率は悪いですが、
それほど問題にならないと思います。

コード:

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

void func(int a[], int n, double d[])
{
	double tmp_d[5], tmp_i;
	int i, sum = 0;
	
	for(i = 0; i < 5; ++ i){
		tmp_d[i] = modf(n * d[i], &tmp_i);
		a[i] = (int)tmp_i;
		sum += a[i];
	}
	srand((unsigned)time(NULL));
	while(sum < n){
		int max = 0;
		
		for(i = 1; i < 5; ++ i){
			if(tmp_d[i] > tmp_d[max] || (tmp_d[i] == tmp_d[max] && rand() % 2)){
				max = i;
			}
		}
		++ a[max];
		++ sum;
		tmp_d[max] = -1;
	}
}

int main(void)
{
	int a[5], n = 6, i;
	double d[5] = {0.3, 0.4, 0.1, 0.1, 0.1};
	
	func(a, n, d);
	for(i = 0; i < 5; ++ i) printf("%d ", a[i]); putchar('\n');
	return 0;
}

閉鎖

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