PDA

View Full Version : سوال: اعداد تصادفی که جمعشان عددی خاص باشد



samin_panahi
دوشنبه 07 بهمن 1392, 16:03 عصر
سلام
می خوام 5 عدد تصادفی بین 1 تا 3 ایجاد کنم
تا اینجا که مشکلی نیست ولی می خوام این اعداد مجموعشون بشه 10
نمی دونم چطور باید اینو نوشت

5 تا عدد [یا 1 یا 2 یا 3] که جمعشون می شه 10
ممنون می شم راهنمایی کنید!

mahdi.compute
دوشنبه 07 بهمن 1392, 16:57 عصر
تست شده !


Random r = new Random();
int X =0;
int[] x = new int[5];
while (X != 10)
{
x[0] = r.Next(0, 4);
x[1] = r.Next(0, 4);
x[2] = r.Next(0, 4);
x[3] = r.Next(0, 4);
x[4] = r.Next(0, 4);
X = x[0] + x[1] + x[2] + x[3] + x[4];
}
textBox1.Text = x[0].ToString() + x[1].ToString() + x[2].ToString() + x[3].ToString() + x[4].ToString();

samin_panahi
دوشنبه 07 بهمن 1392, 17:23 عصر
ممنون
این واسه تعداد کم خوبه
ولی تعداد که زیاد می شه تو حلقه گیر می کنه
مثلا 10 تا عدد که جمعشون بشه 50 و بین 1 تا 7 باشن اعداد....

syntiberium
دوشنبه 07 بهمن 1392, 17:47 عصر
یه listbox1 درست کن
int[] ia1 = new int[5];
int i1 = 0, i2 = 0, i3 = 0;
int inum = 10;//int maximum number
int ico = 5;//int count
int imin = 1;
int imax = 4;
int imaxloop = 1000;//if it pass the 1000 the result is not true

listBox1.Items.Clear();

Random r1 = new Random();
for (int i = 0; i < ico; i++)//creating random numbers
i1 += ia1[i] = r1.Next(imin, imax);

if (i1 == inum)
for (int i = 0; i < ico; i++)
listBox1.Items.Add(ia1[i]);

if (i1 > inum)
{
i2 = i1;
for (int i = 0; i < imaxloop; i++)
{
for (int j = 0; j < imaxloop; j++)
{
i3 = r1.Next(0, ico);
if (ia1[i3] > imin)
{
ia1[i3]--;
i2--;
break;
}
}
if (i2 == inum)
{
for (int j = 0; j < ico; j++)
listBox1.Items.Add(ia1[j]);
break;
}
}
}

if (i1 < inum)
{
i2 = i1;
for (int i = 0; i < imaxloop; i++)
{
for (int j = 0; j < imaxloop; j++)
{
i3 = r1.Next(0, ico);
if (ia1[i3] < imax-1)
{
ia1[i3]++;
i2++;
break;
}
}
if (i2 == inum)
{
for (int j = 0; j < ico; j++)
listBox1.Items.Add(ia1[j]);
break;
}
}
}
الگوریتمش طولانیه ولی همون طور که گفتی برای تعداد بالا توی حلقه گیر نمی کنه .

fmehrvarzi
سه شنبه 08 بهمن 1392, 00:57 صبح
--------------------------------------------------:لبخند:
یک اشکال کوچک داشت(تابع رندم را باید به صورت یک متغیر استاتیک تعریف میکردم تا تکراری نشون نده) اصلاح شد:
static Random _r = new Random();
static int[] Rand(int nMin, int nMax, int K, int M)
{
int _k = K; int[] Rnd = new int[K];
Func<int, int, bool> CS = (k, m) => (k * nMin <= m && m <= nMax * k);
IEnumerable<int> Bquery1 = Enumerable.Range(nMin, nMax - nMin + 1);
for (int i = 0; i < _k; i++)
{
IEnumerable<int> Bquery1Filter = Bquery1.Where(x => CS(K - 1, M - x));
Rnd[i] = Bquery1Filter.ElementAt(_r.Next(0, Bquery1Filter.Count()));
K--;M -= Rnd[i];
}
return Rnd;
}
و این هم نحوه استفاده اش فقط توجه کنید که برای اینکه این تابع را در حلقه قرار دهید حتماً به این پستم در پایین (http://barnamenevis.org/showthread.php?438643-%D8%A7%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AA%D8%B5%D8%A7%D8%AF%D9%81%DB%8C&p=1964159&viewfull=1#post1964159) نگاه کنید
int[] rndArray=Rand(1, 4, 5, 10);

rahnema1
سه شنبه 08 بهمن 1392, 13:38 عصر
اون روش که قبلا گذاشتم و حذف کردم کاملا رندوم نمی داد اما فکر کنم این یکی دیگه رندوم باشه اگه اشکال داشت تذکر بدید
در ضمن تابعی که fmehrvarzi عزیز گذاشتند را امتحان کردم فکر کنم رندوم نباشه یه بار هم خودتون چند بار تست کنید تا مطمئن بشید

int[] RandSum2 (int from1,int to1,int count1,int sum1)
{
to1-=from1;
sum1-=count1*from1;
int sum2=0,ran,mx=to1+1;
Random rr = new Random();
int[] RandArray = new int[count1];
while (mx>to1) {
mx=from1;
do
{
ran=rr.Next(1,Math.Min(to1,sum1-sum2+1));
mx=Math.Max(mx,RandArray[rr.Next(count1)]+=ran);
sum2+=ran;
} while(sum2<sum1);
RandArray=RandArray.Select(x => (int)Math.Round((double)x/mx*(Math.Min(mx,to1)))).ToArray();
sum2=RandArray.Sum();
}
RandArray=RandArray.Select(x => x+from1).ToArray();
return RandArray;
}

واسه انتخاب ده تا عدد که بین 1 تا 7 باشند و جمعشون بشه 50 این دستورشه

int[] myarr=RandSum2(1,7,10,50);

fmehrvarzi
سه شنبه 08 بهمن 1392, 13:53 عصر
در ضمن تابعی که fmehrvarzi عزیز گذاشتند را امتحان کردم فکر کنم رندوم نباشه یه بار هم خودتون چند بار تست کنید تا مطمئن بشید
این تابعی که گذاشتم کاملاً دقیق رندوم هست، اگر خواستی اساس کارش رو شرح میدهم.

mahdi.compute
سه شنبه 08 بهمن 1392, 14:52 عصر
درباره ی این کد یه مقدار توضیح میدی !



اون روش که قبلا گذاشتم و حذف کردم کاملا رندوم نمی داد اما فکر کنم این یکی دیگه رندوم باشه اگه اشکال داشت تذکر بدید
در ضمن تابعی که fmehrvarzi عزیز گذاشتند را امتحان کردم فکر کنم رندوم نباشه یه بار هم خودتون چند بار تست کنید تا مطمئن بشید

int[] RandSum2 (int from1,int to1,int count1,int sum1)
{
to1-=from1;
sum1-=count1*from1;
int sum2=0,ran,mx=to1+1;
Random rr = new Random();
int[] RandArray = new int[count1];
while (mx>to1) {
mx=from1;
do
{
ran=rr.Next(1,Math.Min(to1,sum1-sum2+1));
mx=Math.Max(mx,RandArray[rr.Next(count1)]+=ran);
sum2+=ran;
} while(sum2<sum1);
RandArray=RandArray.Select(x => (int)Math.Round((double)x/mx*(Math.Min(mx,to1)))).ToArray();
sum2=RandArray.Sum();
}
RandArray=RandArray.Select(x => x+from1).ToArray();
return RandArray;
}

واسه انتخاب ده تا عدد که بین 1 تا 7 باشند و جمعشون بشه 50 این دستورشه

int[] myarr=RandSum2(1,7,10,50);

rahnema1
سه شنبه 08 بهمن 1392, 16:03 عصر
من یک مقایسه کردم تابعی که جناب fmehrvarzi گذاشتند با تابعی که خودم گذاشتم می خواهیم 10 تا عدد تولید کنیم که بین 1 تا 7 باشند و جمعشون هم بشه 30 از هر کدوم 8 بار عدد تولید کردم آخرین عدد هر سطر مجموع اعداده
روش fmehrvarzi :


int[] myarr=Rand(1,7,10,30);
7,7,7,3,1,1,1,1,28
3,3,3,3,3,3,3,3,24
3,3,3,3,3,3,3,3,24
4,4,4,4,4,3,2,2,27
2,2,2,2,2,2,2,3,17
2,2,2,2,2,2,2,3,17
7,7,7,3,1,1,1,1,28
5,5,5,5,4,2,1,1,28


روش خودم



int[] myarr=RandSum2(1,7,10,30);
2,1,2,6,3,1,7,2,2,4,30
1,1,2,7,3,6,2,1,5,2,30
6,5,4,1,1,1,2,5,1,4,30
1,1,1,7,7,3,1,2,5,2,30
6,3,1,1,6,1,1,3,6,2,30
4,4,4,2,4,1,1,1,7,2,30
3,1,4,2,3,7,1,4,3,2,30
3,7,2,4,2,6,1,3,1,1,30


روش جناب fmehrvarzi قرار بود 10 تا تولید کنه که می بینیم 8 تا تولید کرده و ثانیا ببینید اعداد کاملا شبیه به هم هستند و ثالثا به آخرین عدد در هر سطر دقت کنید قراره که مجموع اونها 30 بشه که می بینیم 28 و 24 و .. شده حالا نمی دونم از چه متدی استفاده کردید شاید یه جاش اشکال داشته باشه به هر حال اینجور جواب میده قضاوت با خودتون

samin_panahi
سه شنبه 08 بهمن 1392, 16:11 عصر
اون روش که قبلا گذاشتم و حذف کردم کاملا رندوم نمی داد اما فکر کنم این یکی دیگه رندوم باشه اگه اشکال داشت تذکر بدید
سلام و تشکر
تابع رو با این اعداد فراخوانی کنید:
int[] myarr = RandSum2(1, 4, 9, 36);
می خوام نتیجه متفاوت باشه هردفعه....

rahnema1
سه شنبه 08 بهمن 1392, 16:21 عصر
درباره ی این کد یه مقدار توضیح میدی !
ببینید فرض کنید بخواهیم 10 تا عدد تولید کنیم که بین 1 تا 7 باشند و مجموع اونها بشه 30 . ده تا خانه آرایه ایجاد می کنیم
1.داخل خانه های آرایه را با اعداد 1 تا 6 پر می کنیم به طوری که مجموه اونها بشه 20 ( اینکه چرا بشه 20 تا آخر کار معلوم میشه) تا اینکه کدام خانه آرایه انتخاب بشه و اینکه چه عددی در اون قرار بگیره تصادفیه یعنی اگه یک خانه آرایه دو بار انتخاب شد مقدار قبلی را با مقدار جدید جمع می کنیم با این کار ممکنه یک خانه آرایه اصلا عددی بهش اختصاص داده نشه و مقدار اون برابر صفر بشه اما یک خانه آرایه چندین بار عدد بهش اختصاص داده بشه که در این صورت با عدد قبلی که در آن خانه بود جمع میشه این کار در یک حلقه انجام میشه
2.حالا اگه مثلا یک خانه آرایه بیشتر از 6 باشه می آییم کل مقادیر موجود در آرایه را scale می دهیم تا به مقیاس بین 0 تا 6 قرار بگیره اما با این کار مجموع مقادیر آرایه از 20 کمتر میشه دو باره در یک حلقه while دیگه می گیم مرحله 1 تکرار بشه به طوری که مجموع مقادیر اون 20 بشه
این مراحل تکرار میشه و در هر مرحله تعداد اعدادی که باید وارد آرایه بشوند کمتر میشه تا نهایتا مجموع اعداد داخل آرایه برابر 20 میشه و اعداد هم بین 0 و 6 میشن
3.نهایتا به هر کدوم از خانه های آرایه عدد 1 را اضافه می کنیم تا هم مجموع برابر 30 بشه و مقادیر هم بین 1 تا 7 بشن

fmehrvarzi
سه شنبه 08 بهمن 1392, 16:23 عصر
جناب رهنما شما از کدهای قبلیم دارین استفاده میکنید، کدهام اصلاح شدند

یک نمونه از بکار گیری کد پستم (http://barnamenevis.org/showthread.php?438643-%D8%A7%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AA%D8%B5%D8%A7%D8%AF%D9%81%DB%8C&p=1963741&viewfull=1#post1963741) در کنسول اپلیکیشن:
int nMin = 1;
int nMax = 4;
int K = 5;
int M = 10;

for (int i = 0; i < 20; i++)
{
int[] rndArray=Rand(nMin, nMax, K, M);
foreach (int item in rndArray)
{
Console.Write(item + " ");
}
Console.WriteLine("\n");
}
Console.ReadLine();

نتایج:

rahnema1
سه شنبه 08 بهمن 1392, 16:25 عصر
سلام و تشکر
تابع رو با این اعداد فراخوانی کنید:

int[] myarr = RandSum2(1, 4, 9, 36);


دوست من این که محاله جوابشون متفاوت بشه چون 4*9 =36 و شرط هم گذاشتید اعداد از 4 بیشتر نشن

samin_panahi
سه شنبه 08 بهمن 1392, 16:39 عصر
سلام و تشکر
تابع رو با این اعداد فراخوانی کنید:

int[] myarr = RandSum2(1, 4, 9, 36);

دوست من این که محاله جوابشون متفاوت بشه چون 4*9 =36 و شرط هم گذاشتید اعداد از 4 بیشتر نشن

آها، مال شما وقتی می گی 1 و 4 آخرین عددش چهاره!
مال جناب fmehrvarzi تا 5 رو هم در نظر می گیره
یعنی این کد تو مال شما
int[] myarr = RandSum2(1, 4, 9, 36);

با این کد جناب fmehrvarzi برابره

int[] myarr = RandSum2(1, 3, 9, 36);

می شه لطف کنید این تاپیک رو یه نگاهی بندازید و کمکمون کنید؟ لینک (http://barnamenevis.org/showthread.php?438202-%DA%86%DA%AF%D9%88%D9%86%DA%AF%DB%8C-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-Thread-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%AA%D8%BA%DB%8C%DB%8C%D8%B1-%D8%AE%D8%B5%D9%88%D8%B5%DB%8C%D8%A7%D8%AA-%D8%A7%D8%B4%DB%8C%D8%A7)

fmehrvarzi
سه شنبه 08 بهمن 1392, 16:39 عصر
این هم توضیح روشم (http://barnamenevis.org/showthread.php?438643-%D8%A7%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AA%D8%B5%D8%A7%D8%AF%D9%81%DB%8C&p=1963741&viewfull=1#post1963741) البته بصورت تصویری:

rahnema1
سه شنبه 08 بهمن 1392, 17:04 عصر
الان درست شد

fmehrvarzi
سه شنبه 08 بهمن 1392, 17:38 عصر
کدها اصلاح شد. یک نکته جالب خیلی ریز:
اگر از تابع رندم استفاده میکنید حتماً باید آن شی کلاس رندم را به صورت "استاتیک سراسری" تعریف کنید و گرنه نتایج تکراری نشون میدهد.

یعنی به این صورت:
static Random _r = new Random();

و در نتیجه تو نحوه استفاده از فرمول این دستور دیگر نیازی نیست:
System.Threading.Thread.Sleep(164);

منبع:http://www.dotnetperls.com/random

fmehrvarzi
سه شنبه 08 بهمن 1392, 18:29 عصر
اون روش که قبلا گذاشتم و حذف کردم کاملا رندوم نمی داد اما فکر کنم این یکی دیگه رندوم باشه اگه اشکال داشت تذکر بدید
در ضمن تابعی که fmehrvarzi عزیز گذاشتند را امتحان کردم فکر کنم رندوم نباشه یه بار هم خودتون چند بار تست کنید تا مطمئن بشید

int[] RandSum2 (int from1,int to1,int count1,int sum1)
{
to1-=from1;
sum1-=count1*from1;
int sum2=0,ran,mx=to1+1;
Random rr = new Random();
int[] RandArray = new int[count1];
while (mx>to1) {
mx=from1;
do
{
ran=rr.Next(1,Math.Min(to1,sum1-sum2+1));
mx=Math.Max(mx,RandArray[rr.Next(count1)]+=ran);
sum2+=ran;
} while(sum2<sum1);
RandArray=RandArray.Select(x => (int)Math.Round((double)x/mx*(Math.Min(mx,to1)))).ToArray();
sum2=RandArray.Sum();
}
RandArray=RandArray.Select(x => x+from1).ToArray();
return RandArray;
}

واسه انتخاب ده تا عدد که بین 1 تا 7 باشند و جمعشون بشه 50 این دستورشه

int[] myarr=RandSum2(1,7,10,50);


این الگوریتم به دلیل رعایت نکردن همان نکته ای که در مورد نحوه استفاده از کلاس رندوم گفتم (که به صورت استاتیک باید باشد)وقتی که در یک حلقه حتی کوچک قرار میگیرد، اعداد تکراری تولید میکند!

fmehrvarzi
سه شنبه 08 بهمن 1392, 18:53 عصر
برای اعداد بزرگ مثلاً برای
int nMin = 1, nMax = 3000, K = 500, M = 1000000;
الگوریتمم هنوز جواب میدهد ولی الگوریتم جناب رهنما هنگ میکند:
این هم کدهای امتحان در کنسول:
class Program
{
static void Main(string[] args)
{

int nMin = 1, nMax = 3000, K = 500, M = 1000000;
/***************Fmehrvarzi*******************/
int[] rnd1 = Rand(nMin, nMax, K, M);
Console.WriteLine("******************And The Next****************************");
/***************Rahnama1*******************/
int[] rnd2 = RandSum2(nMin, nMax, K, M);
Console.ReadLine();
}
static Random _r = new Random();

//Rahnama1
static int[] RandSum2(int from1, int to1, int count1, int sum1)
{
to1 -= from1;
sum1 -= count1 * from1;
int sum2 = 0, ran, mx = to1 + 1;
int[] RandArray = new int[count1];
while (mx > to1)
{
mx = from1;
do
{
ran = _r.Next(1, Math.Min(to1, sum1 - sum2 + 1));
mx = Math.Max(mx, RandArray[_r.Next(count1)] += ran);
sum2 += ran;
} while (sum2 < sum1);
RandArray = RandArray.Select(x => (int)Math.Round((double)x / mx * (Math.Min(mx, to1)))).ToArray();
sum2 = RandArray.Sum();
}
RandArray = RandArray.Select(x => x + from1).ToArray();
return RandArray;
}

//Fmehrvarzi
static int[] Rand(int nMin, int nMax, int K, int M)
{
int _k = K; int[] Rnd = new int[K];
Func<int, int, bool> CS = (k, m) => (k * nMin <= m && m <= nMax * k);
IEnumerable<int> Bquery1 = Enumerable.Range(nMin, nMax - nMin + 1);
for (int i = 0; i < _k; i++)
{
IEnumerable<int> Bquery1Filter = Bquery1.Where(x => CS(K - 1, M - x));
Rnd[i] = Bquery1Filter.ElementAt(_r.Next(0, Bquery1Filter.Count()));
K--;M -= Rnd[i];
}
return Rnd;
}
}

علی متقی پور
سه شنبه 08 بهمن 1392, 20:50 عصر
با سلام

جواب ها رو ندیدم ولی فکر نمیکنم مساله مشکلی باشه که لازم بوده باشه اینهمه پست داده بشه. شما کافیه هر بار که یک عدد رندوم بدست میاد از اون عدد مجمودع کم کنید و عدد رندوم بعدی رو از اون کوچیکتر انتخاب کنید. بسیار ساده خواهد بود

samin_panahi
سه شنبه 08 بهمن 1392, 21:26 عصر
با سلام
جواب ها رو ندیدم ولی فکر نمیکنم مساله مشکلی باشه که لازم بوده باشه اینهمه پست داده بشه. شما کافیه هر بار که یک عدد رندوم بدست میاد از اون عدد مجمودع کم کنید و عدد رندوم بعدی رو از اون کوچیکتر انتخاب کنید. بسیار ساده خواهد بود


سلام
اگه اشتباه نکنم این روشی که شما می گید وقتی درسته که در اعداد رندوم محدودیتی وجود نداشته باشه --> برای وقتی که 9 تا عدد می خوام که جمعشون می شه 36
ولی برای وقتی که 9 تا عدد که جمعشون می شه 36 و هیچ کدوم از 5 بیشتر نیستند این روش کار نمی کنه

fmehrvarzi
چهارشنبه 09 بهمن 1392, 03:33 صبح
با سلام

جواب ها رو ندیدم ولی فکر نمیکنم مساله مشکلی باشه که لازم بوده باشه اینهمه پست داده بشه.
شاید مسأله در نگاه اول ساده به نظر بیاد اما در عمل چیز دیگریست.

rahnema1
چهارشنبه 09 بهمن 1392, 06:50 صبح
خب من یه تذکر دادم که یه اشکال کوچیک در کد fmehrvarzi وجود داشت که اصلاح شد و حالا بدون تعصب کد ایشان را بر کد خودم ترجیح می دهم اما در مورد عدد رندوم فکر نکنم حتما لازم باشه گلوبال و از نوع استاتیک باشه فقط لازمه که یک آبجکت رندوم را درست کنیم و به تعداد زیاد از متد next استفاده کنیم که من این کار را انجام دادم چون seed فقط هنگام ایجاد آبجکت رندوم تعیین میشه اما اگه مرتبا پشت سر هم شی ء رندوم ایجاد بشه seed ها ممکنه یکسان بشه