Kaprekar constant(卡普雷卡爾黑洞)


昨天在朋友的微博里看到一條關於數字迭代的有趣的題目。然后正好自己剛剛放假就沒事寫寫,正好檢驗下我最近算法是否提高,其中彎路很多,追求在多次實踐中來鍛煉自己的邏輯和編碼能力。

其中描述是:

把一個四位數的四個數字由小至大排列,組成一個新數,又由大至小排列排列組成一個新數,這兩個數相減,之后重復這個步驟,只要四位數的四個數字不重復,數字最終便會變成 6174。

例如:
3109,
9310 - 0139 = 9171,
9711 - 1179 = 8532,
8532 - 2358 = 6174。
而 6174 這個數也會變成 6174,7641 - 1467 = 6174。
任取一個四位數,只要四個數字不全相同,按數字遞減順序排列,構成最大數作為被減數;按數字遞增順序排列,構成最小數作為減數,其差就會得6174;如不是6174,則按上述方法再作減法,至多不過10步就必然得到6174。
但是其中需要8步的初始數,我還沒找(我把99999個隨機數所轉換數據導入到txt中,大小為8M,也沒找到)
一個7步的示例:
如取四位數5679,按以上方法作運算如下:
9765-5679=4086 8640-4068=4572 7542-2457=5085
8550-5058=3492 9432-2349=7083 8730-3078=5652
6552-2556=3996 9963-3699=6264 6642-2466=4176
7641-1467=6174
 
其中c#實現代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;


namespace ConsoleApplication3
{
    class Program
    {
        static int[] rnd;
        static int N = 0;
        const int result = 6174;
        static Random rn = new Random();
        static StringBuilder output = new StringBuilder();

        static void Main(string[] args)
        {
            for (int i = 0; i < 99999; i++)
            {
                rndArr(4);
                output.AppendLine("初始數為:" + arrToint(rnd).ToString());
                output.Append("差值過程數分別為:");
                if (function(rnd))
                {
                    output.AppendLine("執行次數為" + N.ToString() + "");
                    output.AppendLine("");
                    N = 0;
                }
            }
            try
            {
                string filepath = "d:/1.txt";
                FileStream fs = new FileStream(filepath, FileMode.Create);
                StreamWriter sw = new StreamWriter(fs);
                sw.Write(output);
                sw.Close();
                Console.WriteLine("success!");
                Console.WriteLine("已經寫到" + filepath);
            }
            catch { Console.Write("0"); }
            Console.ReadKey();
        }
        /// <summary>
        /// 迭代求計算次數
        /// </summary>
        /// <param name="rTemp">差值循環</param>
        /// <returns>找到固定值返回True</returns>
        static bool function(int[] rTemp)
        {
            cba(rnd); //整理成可轉換成最大值的int[]
            int newint = arrToint(rTemp) - arrTointR(rTemp);
            N++;
            output.Append(newint + ",");
            if (newint == result)
            {
                return true;
            }
            else return function(cba(intToarr(newint)));
        }
        /// <summary>
        /// 數組轉換成數值(確保參數為最大值)
        /// </summary>
        /// <param name="a"></param>
        /// <returns>最大值</returns>
        static int arrToint(int[] a)
        {
            string temp = "";
            for (int i = 0; i < a.Length; i++)
                temp += a[i].ToString();
            return Int16.Parse(temp);
        }
        /// <summary>
        /// 將數組反向再轉換成數值(確保參數為最大值)
        /// </summary>
        /// <param name="a"></param>
        /// <returns>最小值</returns>
        static int arrTointR(int[] a)
        {
            string temp = "";
            for (int i = 0; i < a.Length; i++)
                temp += a[a.Length - i - 1].ToString();
            return Int16.Parse(temp);
        }
        /// <summary>
        /// int值轉成數組
        /// </summary>
        /// <param name="a"></param>
        /// <returns></returns>
        static int[] intToarr(int a)
        {
            int length = a.ToString().Length;
            int[] re = new int[length];
            for (int i = 0; i < length; i++)
            {
                re[i] = a / Convert.ToInt16(Math.Pow(10, length - 1 - i));
                a = a - re[i] * Convert.ToInt16(Math.Pow(10, length - 1 - i));
            }
            return re;
        }
        /// <summary>
        /// 產生初始隨機數組
        /// </summary>
        /// <param name="length"></param>
        static void rndArr(int length)
        {
            rnd = new int[length];
            int[] rndtemp = new int[rnd.Length];
            for (int i = 0; i < length; i++)
            {
                do
                {
                    rndtemp[i] = rn.Next(10);
                }
                while (validate(rndtemp, rndtemp[i], i) || rndtemp[0] == 0);
            }
            rnd = rndtemp;
        }

        /// <summary>
        /// Random Validate 如果存在返回true
        /// </summary>
        /// <param name="v"></param>
        /// <param name="x">當前序號標記</param>
        /// <returns></returns>
        static bool validate(int[] temp, int v, int x)
        {
            int k = 0;
            for (int i = 0; i < x; i++)
            {
                if (temp[i] == v)
                    k++;
            }
            if (k > 0) return true;
            return false;
        }
        /// <summary>
        /// 隨機數組轉換成最大值數組
        /// </summary>
        /// <param name="temp"></param>
        /// <returns></returns>
        static int[] cba(int[] temp)
        {
            for (int i = 0; i < temp.Length - 1; i++)
            {
                for (int j = 0; j < temp.Length - i - 1; j++)
                {
                    if (temp[j] < temp[j + 1])
                    {
                        temp[j] = temp[j] + temp[j + 1];
                        temp[j + 1] = temp[j] - temp[j + 1];
                        temp[j] = temp[j] - temp[j + 1];
                    }
                }
            }
            return temp;
        }
    }
}

 其中用到了迭代算法,這算是第一次嘗試,路漫漫,其中可能有一定多繞步,過路人可以指出,在下在這感謝各位。

參考資料:http://en.wikipedia.org/wiki/D._R._Kaprekar#cite_note-4

下面是網友給出的利用Linq寫的算法:

        static void Main(string[] args)
        {
            Process(1234, 1);
            Console.ReadKey();
        }
        private static void Process(int number, int deep)
        {
            var numbers = new int[] { number % 10, (number % 100) / 10, (number % 1000) / 100, number / 1000 };
            var ascOrder = numbers.OrderBy(n => n).ToArray();
            var descOrder = numbers.OrderByDescending(n => n).ToArray();
            var weiQuan = 10000;
            var smaller = ascOrder.Select(a =>
            {
                weiQuan = weiQuan / 10;
                return a * weiQuan;
            }).Sum();
            weiQuan = 10000;
            var bigger = descOrder.Select(a =>
            {
                weiQuan = weiQuan / 10;
                return a * weiQuan;
            }).Sum();
            var diff = bigger - smaller;
            Console.WriteLine(string.Format("第{4}次:{0}:{1}-{2}={3}", number, bigger, smaller, diff, deep));
            if (diff == number)
            {
                Console.WriteLine("That's just right");
                return;
            }
            else if (deep >= 10)
            {
                Console.WriteLine("計算次數超過10次,尚未證明結果,退出");
                return;
            }
            else
            {
                Process(diff, ++deep);
            }
        }

首先我在隨機4個數里面寫了算法,然后在排序里面也相對寫復雜了,網友這算法正是突顯Linq編碼優勢的地方。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM