算法 - 比賽得分可能數
1 介紹
2 實現
2.1 分析
2.2 算法一
2.3 算法二
2.4 算法三
1 介紹
以排球比賽分例,默認情況下,A、B 兩隊比賽時,率先得到 25 分得將取勝。但若雙方打成 24:24 時,則最高得分將變為 26 分。以后情況以此類推,例如,理論上可以打出諸如 40:42 這樣的結局。
算法的要求是,在已知最終比分的情況下,算出能夠達到該最終比分的所有可能得分順序。
例1:如果最終比分是 0:25,那么只有一種順序,那就是:
0:1 → 0:2 → 0:3 → ... 0:24 → 0:25
例2:如果最終比分是 1:25,那么可能有 25 種情況,例如:
1:0 → 0:1 → 0:2 → 0:3 → ... 0:24 → 0:25
0:1 → 1:1 → 1:2 → 1:3 → ... 1:24 → 1:25
0:1 → 0:2 → 1:2 → 1:3 → ... 1:24 → 1:25
......
例3:如果最終比分是 3:25,將有 2925 種情況
例4:如果最終比分是 3:12,結果為 0,因為不可能有這種情況的最終比分
要求編寫程序實現該功能,可以支持的最大比分數為 40。
2 實現
2.1 分析
很容易想到,比賽的可能路徑可以使用如下的二叉樹來分析,紅色節點表示為不可能的分支
本例中的算法使用 C# 實現
首先不管算法如何,先把一些公共的判斷函數寫在這里,以后其它例子都會用
// 是否有效最終比分
const int MAX = 25; static bool IsValid(int A, int B) { if (A < MAX && B < MAX) { return false; } if (Math.Abs(A - B) < 2) { return false; } if (Math.Max(A, B) > MAX && Math.Abs(A - B) != 2) { return false; } return true; } // 是否為有效中間比分,例如如果最終比分為 3:25,中間不可能出現 2:25(已經贏了不用再打了) static bool IsValidPath(int A, int B, int finalA, int finalB) { if (A > finalA || B > finalB) { return false; } if (IsWinStatus(A, B)) { return A == finalA && B == finalB; } else { return true; } } // 是否獲勝 static bool IsWinStatus(int A, int B) { if (Math.Max(A, B) == MAX && Math.Abs(A - B) >= 2) { return true; } if (Math.Max(A, B) > MAX && Math.Abs(A - B) == 2) { return true; } return false; }
2.2 算法一
很容易想到第一種算法,就是試圖生成上圖中的二叉樹,如果生成出一個最終葉子結點(例如 3:25)則將計數器加 1,如下所示
class Model1 { static void Main(string[] args) { int a = CalcScore1(7, 25); Console.WriteLine("Result: " + a); Console.Read(); } // 計算可能得分的入口函數 static int CalcScore1(int A, int B) { if (!IsValid(A, B)) { return 0; } Node rootNode = new Node(0, 0); int counter = 0; Constuct(rootNode, A, B, ref counter); return counter; } private static void Constuct(Node node, int finalA, int finalB, ref int counter) { if (node.ValueA == finalA && node.ValueB == finalB) { counter++; } else { if (node.ValueA < finalA && IsValidPath(node.ValueA + 1, node.ValueB, finalA, finalB)) { node.Left = new Node(node.ValueA + 1, node.ValueB); } if (node.ValueB < finalB && IsValidPath(node.ValueA, node.ValueB + 1, finalA, finalB)) { node.Right = new Node(node.ValueA, node.ValueB + 1); } } if (node.Left != null) { Constuct(node.Left, finalA, finalB, ref counter); } if (node.Right != null) { Constuct(node.Right, finalA, finalB, ref counter); } } class Node { public Node(int A, int B) { this.ValueA = A; this.ValueB = B; } public int ValueA { get; set; } public int ValueB { get; set; } public Node Left { get; set; } public Node Right { get; set;