منتدى فيجوال بيسك لكل العرب | منتدى المبرمجين العرب

نسخة كاملة : [مسابقة الخوارزمية 3] - الجولة الثالثة
أنت حالياً تتصفح نسخة خفيفة من المنتدى . مشاهدة نسخة كاملة مع جميع الأشكال الجمالية .
الصفحات : 1 2 3 4 5 6 7 8
3?? : 98?
Participant answer: 098 : 103
My answer: 098 : 093

Similarity Failed


---


يرجى الانتباه انه الساعة 12 ليلا سيتم اغلاق الجولة.
هذا هو الحل والحمد لله
?

عفوآ نسيت وضع ملفات التكست
يبدو ان برنامجك لايعمل على جهازي بشكل جيد بسبب اختلاف الCulture ?!

المهم

اريد output هذين الملفين ، شغل البرنامج عندك وارفع لي الـ outputq1.txt + outputq2.txt
والله العظيم ده آخر مرة
جت جت مجتشى مجتش
توليد الملف النصي خاطئ فعلا..

المهم سأحتسب النقطتين لان لو جمعنا الحل الاول والاخير الذي قمت به ، سيكون الحل صحيحا Smile
شكرآ لك ألف شكر
فموضوع التعامل مع ملفات النصوص موضوع جديد على
لأن تخصصى فى برمجة الخوارزميات نفسها فقط
Smile انتهت الجولة الثالثة



وترتيب المتسابقين هو :

10 نقاط للأخ اسلام الكبابي
8 نقاط للإخ عبدالله الصافي
6 نقاط للاخ Fantastico





جميع المشاركين حصلو على +2 بسبب تحقيقهم شرط (الاصغر الاقرب)





تنفيذ الخوارزمية

بما ان هذه الخوارزمية هي اكثر خوارزمية سببت الجدل في جميع مسابقات المنتدى ، فضلت ان اقوم بشرح كيفية تنفيذها بإسهاب كبير حتى تنتشر الفائدة بين الجميع ..

علما بأن طريقة الحل المستخدمة في هذا الرد هي طريقة خاصة بالدوت نت ، وبالاخص (السي شارب) بسبب ان الاكواد المستخدمة في الحل نفسها تستخدم تقنيات لاتتوفر الا في الـ .Net Framework وكل هذا لكي يكون كود الخوارزمية نظيفا ورائعا وقابلا للفهم . Big Grin


-----------


1-  الدوال المُساعدة




في البداية ، قمنا بإنشاء Extension Methods (الدوال الممتدة) وهي دوال مُساعدة أنشأناها لتساعدنا في حل الخوارزمية ( مجرد دوال مساعدة لاشغل لها بالخوارزمية الفعلية) ..


الدوال الممتدة هي احدى ميزات الدوت نت ولمن لايعرف اهميتها ، فهي باختصار.. مجرد دوال تستطيع الوصول اليها من المتغير مباشرة :



PHP كود :
public static class MyExtensions
{
 
   //إستبدال حرف مكان حرف بالاندكس
 
   public static string ReplaceAt(this string strint indexstring replace)
 
   {
 
       return str.Remove(index1).Insert(indexreplace);
 
   }

 
   //حذف علامات الاستفهام واستبدالها بالاصفار
 
   public static string WithoutQMarks(this string str)
 
   {
 
       string final = string.Empty;

 
       foreach (var item in str)
 
           if (item != '?'
 
               final += item;
 
           else 
                final 
+= '0';

 
       return final;
 
   }

 
   //جلب مواقع علامات الاستفهام
 
   public static int[] QMarksIndexes(this string str)
 
   {
 
       List<intindexes = new List<int>();

 
       for (int i 0str.Lengthi++)
 
           if (str[i] == '?')
 
               indexes.Add(i);

 
       return indexes.ToArray();
 
   }
 



وظائف الدوال موضحة بالتعليقات الخضراء ، وكما ترون .. هذه الدوال ممتدة هي مجرد دوال مساعدة سنستخدمها لاحقا ..
الفائدة العظمى من الدوال الممتدة هي امكانية الوصول اليها من المتغير مباشرة ، فلاحظ الكود التالي :-
PHP كود :
           string myStr "?33:?4?";
 
           myStr myStr.WithoutQMarks();  //033:040
 
           //من المتغير مباشرة WithoutQMarks تم الوصول للدالة الممتدة 

انا احب الدوال الممتدة اكثر من الدوال العادية في امور معالجة الـ Datatype وذلك بسبب انها تحقق احد مبادئ كتابة الكود  high cohesion (عزل الاكواد)



انتهينا من كتابة الدوال الممتدة المساعدة للخوارزمية ، ننتقل للكود الرئيسي :-






2- الكود الرئيسي


PHP كود :
       static string CloseMatch(string s1string s2)
 
       {

 
           //مخزنين لتخزين القيم المحتملة
 
           List<intvalues1 = new List<int>();
 
           List<intvalues2 = new List<int>();

 
           //جلب مواقع علامات الاستفهام
 
           int[] s1_Q_Indexes s1.QMarksIndexes();
 
           int[] s2_Q_Indexes s2.QMarksIndexes();

 
           //اضافة القيم الاولية الى اللستة
 
           values1.Add(int.Parse(s1.WithoutQMarks()));
 
           values2.Add(int.Parse(s2.WithoutQMarks()));

 
           //دالة تكرارية لايجاد المجهول
 
           FillUnknown(ref values1ref s1ref s1_Q_Indexes0);
 
           FillUnknown(ref values2ref s2ref s2_Q_Indexes0);

 
           //(حذف المكرر + الترتيب من الاصغر (لتحقيق شرط الاقرب الاصغر
 
           values1 values1.Distinct().OrderBy(=> s).ToList();
 
           values2 values2.Distinct().OrderBy(=> s).ToList();


 
           //جلب الفرق الاقرب
 
           int min int.MaxValuemin_S1 0min_S2 0;
 
           values1.ForEach(v1 => values2.ForEach(v2 =>
 
           {
 
               int absoluteMin Math.Abs(v1 v2);
 
               if (min absoluteMin)
 
               {
 
                   min_S1 v1;
 
                   min_S2 v2;
 
                   min absoluteMin;
 
               }
 
           }));


 
           //اضافة اصفار اذا كان الناتج اقل من طول المدخل
 
           string out_S1 min_S1.ToString().PadLeft(s1.Length'0');
 
           string out_S2 min_S2.ToString().PadLeft(s2.Length'0');

 
       
            return string
.Format("{0} : {1}"out_S1out_S2);
 
       



الان نبدأ بشرح الاكواد جزء جزء :-


1 :
PHP كود :
           //مخزنين لتخزين القيم المحتملة
 
           List<intvalues1 = new List<int>();
 
           List<intvalues2 = new List<int>(); 

2 لست لتخزين القيم المحتملة ، كل لست يخزن القيم المحتملة لجزء من العينة
values1 : values2





2:
PHP كود :
           //جلب مواقع علامات الاستفهام
 
           int[] s1_Q_Indexes s1.QMarksIndexes();
 
           int[] s2_Q_Indexes s2.QMarksIndexes(); 

المتغير s1 يشير الى الجزء الايسر من العينة
المتغير s2 يشير الى الجزء الايمن من العينة


هنا نستعمل الدالة الممتدة  ، لجلب مواقع علامات الاستفهام في العينة .



3:
PHP كود :
           //اضافة القيم الاولية الى اللستة
 
           values1.Add(int.Parse(s1.WithoutQMarks()));
 
           values2.Add(int.Parse(s2.WithoutQMarks())); 

حذف علامات الاستفهام من جميع العينة واستبدالها بأصفار ثم نضيفها للستة القيم المحتملة .



4:


PHP كود :
           //دالة تكرارية لايجاد المجهول
 
           FillUnknown(ref values1ref s1ref s1_Q_Indexes0);
 
           FillUnknown(ref values2ref s2ref s2_Q_Indexes0); 

قلب الخوارزمية ، استدعاء الدالة التكرارية (Recursive Method)
سنشرح ماذا تفعل هذه الدالة بالتفصيل لاحقا .

ولكن هذه الدالة باختصار ـ تملأ الـ 2 لست  بجميع القيم المحتملة للعينة.


5:
PHP كود :
           //(حذف المكرر + الترتيب من الاصغر (لتحقيق شرط الاقرب الاصغر
 
           values1 values1.Distinct().OrderBy(=> s).ToList();
 
           values2 values2.Distinct().OrderBy(=> s).ToList(); 

الشرط الذي جنن الجميع ، شرط جلب الاقرب الاصغر عند تساوي الفرق

هنا استعملنا احدى تقنيات الدوت نت ، Linq ، واستخدمنا Distinct لحذف القيم المكررة
واستخدمنا OrderBy للترتيب من الاصغر للاكبر .

هذين الكودين مجرد تمهيد للكود القادم ...




6:
PHP كود :
           //جلب الفرق الاقرب
 
           int min int.MaxValuemin_S1 0min_S2 0;
 
           values1.ForEach(v1 => values2.ForEach(v2 =>
 
           {
 
               int absoluteMin Math.Abs(v1 v2);
 
               if (min absoluteMin)
 
               {
 
                   min_S1 v1;
 
                   min_S2 v2;
 
                   min absoluteMin;
 
               }
 
           })); 

هنا استعملنا Linq مجددا (كم اشفق على اللغات التي لايوجد لديها Linq ) Sleepy   >> والهدف من الكود واضح
وهو الدوران على اللستة الاولى ، وعند كل دورة ،  يتم الدوران على اللستة الثانية وحساب الفرق في القيم.




7:
PHP كود :
           //اضافة اصفار اذا كان الناتج اقل من طول المدخل
 
           string out_S1 min_S1.ToString().PadLeft(s1.Length'0');
 
           string out_S2 min_S2.ToString().PadLeft(s2.Length'0');

 
       
            return string
.Format("{0} : {1}"out_S1out_S2); 

النهاية الدراماتكية عند هذه الاكود ، فبعد جلب قيم s1 وs2 الاصغر والاقرب ، هنا اول سطرين يقومان بمعادلة طول الoutput مع طول الInput من خلال اضافة الاصفار..

مثلا :
3??:?2?
يجب ان يظهر:
023:023

وليس
23:23


واخيرا يتم ارجاع الناتج الى الدالة الرئيسية في البرنامج وهي main لتقوم بطباعة الناتج المرجع.





3- الدالة القلب في الخوارزمية



واخيرا ، نعرض الدالة المسؤولة عن ملأ علامات الاستفهام بشكل صحيح ، وهي دالة Recursive وقد تم شرح قصة الـ Recursive Method في المقالة التالية :

[مقال] الـ Recursive Methods


PHP كود :
       //Recursive Function - دالة تستدعي نفسها
 
       static void FillUnknown(ref List<intvaluesref string sref int[] qmarksIndexesint startIndex)
 
       {
 
           for (; startIndex s.LengthstartIndex++)
 
           {
 
               if (qmarksIndexes.Contains(startIndex))
 
               {
 
                   for (int c 0<= 9c++)
 
                   {
 
                       //استبدال موقع علامة الاستفهام بمتغير اللوب
 
                       s s.ToString().ReplaceAt(startIndexc.ToString());
 
                       values.Add(int.Parse(s.WithoutQMarks()));

 
                       //الاستدعاء الذاتي للدالة ، مع زيادة الاندكس
 
                       FillUnknown(ref valuesref sref qmarksIndexesstartIndex 1);
 
                   }
 
               }
 
           }
 
       



يمكنكم تتبع الدالة سطرا سطرا لتعرفون كيف تعمل ، ولكن هذه الصورة تشرح لكم كيف تعمل بشكل بسيط جدا :


Now s1 List Filed with all possible values


ويتم استدعاء الدالة مرة اخرى لجلب جميع القيم المحتملة لs2 وتخزينها في الValues2 لست Cool


--


المشروع :
[attachment=12776]


تم - الرجاء من الجميع ارفاق السورس كود
بارك الله فيك ومبروك للفائزين

يعطيك الصحة
الصفحات : 1 2 3 4 5 6 7 8