編碼也快樂:兩隻水壺C#程式

空軍發表於2013-04-10

我的 C# 程式:

using System;
using System.Collections.Generic;

static class Pot2
{
  static int[] Max = { 5, 6 }; // 每隻壺的最大容量,可為任意正整數
  static int[] Pot = { 0, 0 }; // 每隻壺的當前水位
  static List<int[]> SL = new List<int[]>(); // 記錄水位
  static List<int[]> SA = new List<int[]>(); // 記錄動作

  static void Main()
  {
    Pot[0] = 3;  // <------ 這是要從池塘中取的水量,可為任意正整數
    if (Pot[0] < 0 || Pot[0] > Max[0] || Pot[1] < 0 || Pot[1] > Max[1])
    {
      Console.WriteLine("引數超過允許範圍。");
      return;
    }
    // 如果水量不是兩隻壺的最大容量的最大公約數的整數倍,則無解
    if ((Pot[0] + Pot[1]) % Gcd(Max[0], Max[1]) != 0)
    {
      Console.WriteLine("無解。");
      return;
    }
    SL.Add(new int[]{ Pot[0], Pot[1] });
    Solve();
    SA.Add(new int[]{ 0, 0 });
    Print();
  }

  // 返回兩個非負整數的最大公約數
  static int Gcd(int a, int b)
  {
    if (b == 0) return a;
    return Gcd(b, a % b);
  }

  // 解題:反過來思考,先假設已成功,如果最後能得到兩隻空壺就OK了
  static void Solve()
  {
    if      (Pot[0] == 0 && Pot[1] == 0) return;
    else if (Pot[0] == 0 && Pot[1] == Max[1]) Del(1);
    else if (Pot[1] == 0 && Pot[0] == Max[0]) Del(0);
    else if (Pot[0] == 0 || Pot[1] == 0)
    {
      int i = (Pot[0] == 0) ? 0 : 1;
      int j = (Pot[0] == 0) ? 1 : 0;
      Add(i);
      while (Pot[i] > 0)
      {
        Mov(i);
        if (Pot[j] == Max[j]) Del(j);
      }
      if (Pot[i] == 0 && Pot[j] == 0) return;
    }
    else return;
    Solve();
  }

  // 第i壺加滿水
  static void Add(int i)
  {
    Pot[i] = Max[i];
    SL.Add(new int[]{ Pot[0], Pot[1] });
    SA.Add(new int[]{ 1, i });
  }

  // 清空第i壺
  static void Del(int i)
  {
    Pot[i] = 0;
    SL.Add(new int[]{ Pot[0], Pot[1] });
    SA.Add(new int[]{ 2, i });
  }

  // 第i壺的水儘量倒住另一壺
  static void Mov(int i)
  {
    int j = (i + 1) % 2;
    int x = Math.Min(Max[j] - Pot[j], Pot[i]);
    Pot[i] -= x;
    Pot[j] += x;
    SL.Add(new int[] { Pot[0], Pot[1] });
    SA.Add(new int[] { 3, j });
  }

  static string[] Action = {"初始狀態       ", "清空第{0}壺      ", "加滿第{0}壺      ", "第{0}壺倒往另一壺"};

  // 列印解題過程
  static void Print()
  {
    Console.WriteLine("兩隻壺的最大容量分別是 -- [{0}, {1}]", Max[0], Max[1]);
    // 實際操作是前面的解題過程的逆序,因為解題思路是反過來考慮的。
    for (int i = SL.Count - 1; i > 0; i--)
    {
      Console.Write("步驟{0,2} ", SL.Count - 1 - i);
      Console.Write(Action[SA[i][0]], SA[i][1] + 1);
      Console.WriteLine(" -> ({0}, {1})", SL[i][0], SL[i][1]);
    }
    Console.WriteLine("成功!");
  }
}

輸出:

兩隻壺的最大容量分別是 -- [5, 6]
步驟 0 初始狀態        -> (0, 0)
步驟 1 加滿第1壺       -> (5, 0)
步驟 2 第1壺倒往另一壺 -> (0, 5)
步驟 3 加滿第1壺       -> (5, 5)
步驟 4 第1壺倒往另一壺 -> (4, 6)
步驟 5 清空第2壺       -> (4, 0)
步驟 6 第1壺倒往另一壺 -> (0, 4)
步驟 7 加滿第1壺       -> (5, 4)
步驟 8 第1壺倒往另一壺 -> (3, 6)
成功!

社群的程式碼字型似乎是兩個半形字元比一個全形字元略寬,沒能對齊。

相關文章