標籤:

成為數獨高手有哪些好的訓練方法?

除了勤奮之外。


首先平時訓練和比賽是兩回事。
比賽的目的是最快的完成題目,可以用一切非正常手段。比如試數,也就是普通愛好者講的假設法。但實際上標準數獨的邏輯解法里不存在假設的方法。
訓練的目的是有針對性的練習解法,對題目的要求非常高。如果題目質量好有針對性,一天練20道題就足夠,如果題目千篇一律沒有特點,練200道題效果都不會很好。
做題寫小標提示是很有必要的,因為不清楚題目難度,有些難題必須有小標。看世界冠軍在世錦賽決賽中做題也依然是做小標的。當然小標不是候選數全標,而是標註區塊和數對。
標註練好的基礎上再訓練變形規則題目。
更多的訓練、比賽心得可以參考我的博客:http://blog.sina.com.cn/chencensudoku


要好好練的話,初期要學做記號。
每格分成9個小格,對應9個數字。在可能的數字處點上小點。
然後就是消除記號了,這時有很多決竅。就自己網上查一下吧,總之有了記號一切都一目了然,消除的速度特別快。
我印像里最壞的情況,就是碰到很多格子只有兩種可能。這時需要做個假設,然後推出矛盾。這應該是最高級技巧了。

據我所知,很多數獨遊戲軟體都有記號功能。
先帶記號練,這樣對各種情況有個基本了解,熟了再扔掉記號練。
有時碰到很難的數獨,記號還是必需的。

下面是個我查到的數獨策略,第二個專門解釋如何用記號
http://www.chessandpoker.com/sudoku-strategy-guide.html
http://www.learn-sudoku.com/pencil-marks.html
但是在我看來這還不全,高級戰術完全沒有。


50毫秒內解決數獨問題
這應該是我想到的解決數獨的最好方法了
首先,你需要做好禿頂,長痘,失眠多夢,看誰都sb,誰看你都覺得你情商低的心理準備
當然你還可能遇上美麗的尿尿聲音很大的女程序猿 @劉贊贊
然後開始學習各類編碼,然後編寫演算法,然後運行,然後看著數獨問題解除
喏,就像這樣去50毫秒解決數獨:

// 優化

int CNumMatrix::Optimize()

{

  int x, y;

  int i;

  bool changed = true;

  while(changed)

  {

    changed = false;

    for(x = 0; x &< m_iSize; x++)

    {

      for(y = 0; y &< m_iSize; y++)

      {

        if(NumTrans(m_i16mMatrix[x][y]) == 0)

        {

          return -1;

        }

        if(m_cmPossible[x][y] == 1)

        {

          m_cmPossible[x][y] = 0;

          for(i = 0; i &< m_iSize; i++)

          {

            // 減少列可能性

            if(m_cmPossible[x][i] &> 0)

            {

              this-&>RemovePossible(x, i, m_i16mMatrix[x][y]);

              if(m_cmPossible[x][i] == 0)

              {

                return -1;

              }

            }

            // 減少行可能性

            if(m_cmPossible[i][y] &> 0)

            {

              this-&>RemovePossible(i, y, m_i16mMatrix[x][y]);

              if(m_cmPossible[i][y] == 0)

              {

                return -1;

              }

            }

            // 減少區域可能性

            if(!RemoveRegionPossible(m_cmRegion[x][y], m_i16mMatrix[x][y]))

            {

              return -1;

            }

          }

          m_iAssured++;

          changed = true;

        }

      }

    }

  }

  return 0;

}

// 數字翻譯

int CNumMatrix::NumTrans(__int16 mask)

{

  mask = ~(0xffff &<&< m_iSize);

  if(mask &>= -1 mask &< 3)

  {

    return mask;

  }

  switch(mask)

  {

  case 0x0004:

    return 3;

  case 0x0008:

    return 4;

  case 0x0010:

    return 5;

  case 0x0020:

    return 6;

  case 0x0040:

    return 7;

  case 0x0080:

    return 8;

  case 0x0100:

    return 9;

  case 0x0200:

    return 10;

  case 0x0400:

    return 11;

  case 0x0800:

    return 12;

  case 0x1000:

    return 13;

  case 0x2000:

    return 14;

  case 0x4000:

    return 15;

  case 0x8000:

    return 16;

  }

  return -1;

}

// 從文件讀取

bool CNumMatrix::ReadFile(LPCTSTR fileName)

{

  FILE * fp = fopen(fileName, "r");

  if(fp)

  {

    int x, y;

    char stmp[] = " ";

    int tmp;

    fscanf(fp, "%d %d, %d ", m_iSize, m_ivRegion[0], m_ivRegion[1]);

    if(m_iSize &> 0 m_iSize &<= NM_MAX_SIZE Init())

    {

      for(y = 0; y &< m_iSize; y++)

      {

        for(x = 0; x &< m_iSize; x++)

        {

          fscanf(fp, "%c", stmp[0]);

          if(stmp[0] == "?")

          {

            m_i16mMatrix[x][y] = -1;

            m_cmPossible[x][y] = m_iSize;

          }

          else

          {

            sscanf(stmp, "%X", tmp);

            this-&>SetVal(x, y, NM_MAKE_MASK(tmp));

          }

          fscanf(fp, "%c", stmp[0]);

        }

      }

    }

    else

    {

      fclose(fp);

      return false;

    }

    fclose(fp);

    return this-&>CheckPossibility();

  }

  return false;

}

// 導出到文件

bool CNumMatrix::WriteFile(LPCTSTR fileName)

{

  FILE * fp = fopen(fileName, "w");

  if(fp)

  {

    int x, y;

    int tmp;

    fprintf(fp, "%d %d, %d ", m_iSize, m_ivRegion[0], m_ivRegion[1], m_iAssured);

    for(y = 0; y &< m_iSize; y++)

    {

      for(x = 0; x &< m_iSize - 1; x++)

      {

        tmp = NumTrans(m_i16mMatrix[x][y]);

        if(tmp &>= 0)

        {

          fprintf(fp, "%X ", tmp);

        }

        else

        {

          fprintf(fp, "? ");

        }

      }

      tmp = NumTrans(m_i16mMatrix[x][y]);

      if(tmp &>= 0)

      {

        fprintf(fp, "%X ", tmp);

      }

      else

      {

        fprintf(fp, "? ");

      }

    }

    fclose(fp);

    return true;

  }

  return false;

}

// 減少區域可能性

bool CNumMatrix::RemoveRegionPossible(char region, __int16 mask)

{

  int x, y;

  for(x = 0; x &< m_iSize; x++)

  {

    for(y = 0; y &< m_iSize; y++)

    {

      if(m_cmRegion[x][y] == region m_cmPossible[x][y] &> 0)

      {

        RemovePossible(x, y, mask);

        if(m_cmPossible[x][y] == 0)

        {

          return false;

        }

      }

    }

  }

  return true;

}

// 可能性檢查

bool CNumMatrix::CheckPossibility()

{

  int x, y;

  int i;

  m_iAssured = 0;

  bool zero = false;

  for(x = 0; x &< m_iSize; x++)

  {

    for(y = 0; y &< m_iSize; y++)

    {

      if(m_cmPossible[x][y] == 0)

      {

        m_iAssured++;

      }

      else

      {

        m_cmPossible[x][y] = m_iSize;

        m_i16mMatrix[x][y] = -1;

      }

    }

  }

  if(m_iAssured)

  {

    for(x = 0; x &< m_iSize; x++)

    {

      for(y = 0; y &< m_iSize; y++)

      {

        if(m_cmPossible[x][y] == 0)

        {

          for(i = 0; i &< m_iSize; i++)

          {

            // 減少列可能性

            if(m_cmPossible[x][i] &> 0)

            {

              this-&>RemovePossible(x, i, m_i16mMatrix[x][y]);

              if(m_cmPossible[x][i] == 0)

              {

                return false;

              }

            }

            // 減少行可能性

            if(m_cmPossible[i][y] &> 0)

            {

              this-&>RemovePossible(i, y, m_i16mMatrix[x][y]);

              if(m_cmPossible[i][y] == 0)

              {

                return false;

              }

            }

            // 減少區域可能性

            if(!RemoveRegionPossible(m_cmRegion[x][y], m_i16mMatrix[x][y]))

            {

              return false;

            }

          }

        }

      }

    }

  }

  return true;

}

// 查找解

bool CNumMatrix::FindSolution()

{

  static int si = 0;

  if(Optimize() &< 0)

  {

    return false;

  }

  if(m_iAssured == m_iSize * m_iSize)

  {

    return true;

  }

  CNumMatrix tmp;

  // 查找最小可能性的格子

  int x, y;

  int mx = -1, my = -1;

  char min = m_iSize + 1;

  for(x = 0; x &< m_iSize; x++)

  {

    for(y = 0; y &< m_iSize; y++)

    {

      if(m_cmPossible[x][y] != 0 m_cmPossible[x][y] &< min)

      {

        mx = x;

        my = y;

        min = m_cmPossible[x][y];

      }

    }

  }

  // 取得可能性

  __int16 possible[NM_MAX_SIZE];

  if(mx == -1)

  {

    return false;

  }

  int sum = GetPossibleVal(mx, my, possible);

  // 遍歷可能性

  int i;

  for(i = 0; i &< sum; i++)

  {

    memcpy(tmp, this, sizeof(CNumMatrix));

    tmp.SetVal(mx, my, possible[i]);

    if(tmp.CheckPossibility() tmp.FindSolution())

    {

      memcpy(this, tmp, sizeof(CNumMatrix));

      return true;

    }

  }

  return false;

}


微博上喜歡的小姐姐,是個數獨愛好者。
我就抱著打發時間的想法,先去淘寶買了些一共是十本。起初,做初級的時候,一道可以一個小時,還是做不出來的那種,更多的是做到最後發現是錯誤的。因為工作性質的原因,有時候真的超級閑,就一天一天做,錯了拿橡皮擦了又擦。
也許是掌握了些技巧,或者是不想之前急於攻克,慢慢起來,不僅可以做出來,而且會樂於其中。什麼開發左右腦,我都20多歲了,也沒想著開發啥,初意就是看看是什麼。
所以呀,真的沒有什麼特質或者什麼心思,就是簡單的,我現在就在每天堅持做數獨。


之前同事周大牛數獨玩出花的手段就是自己寫了個數獨破解程序,破解數獨經典題庫的速度比之前世界第一的那個程序快一大截。沒記錯的話是12左右個微秒(後面有時間給大家找下機器配置和源碼地址)。
不是我自己的東西,所以還是匿了。


真沒想到數獨還有世錦賽?!
以前玩的時候網上搜到的數獨遊戲技巧。數獨遊戲技巧(圖解)


多做一些特定的解法的題,記住一些常用的辦法,多上論壇跟別人交流,最好就是有人一起做,很好玩的..


多練習就很快了。
我之前有部諾基亞的6300,裡面有個Flash的數獨,每天利用空閑的時候玩會,從easy到hard有200關,我玩到199關。速度越來越快。


自己要有興趣,然後沒事就玩這個,隨時玩。不開心的時候也玩。多了發現自己掌握的技巧會越來越多,拿過來一個數獨,自己就會用最快的速度,將不同的方法一遍遍的過,一個個解決


推薦閱讀:

一道編程/數學挑戰題,應如何思考?
網上看到一道數學題,關於dota天梯分的。?

TAG:數學競賽 |