開啟章節選單
441 Lotto
題目連結
題目敘述
在德國樂透中,你必須從集合 {1,2,...,49} 中選出 6 個數字
雖然這樣做並不會增加中獎的機率,但一種常見的策略是選擇一個包含 k 個數字的子集合 S(k > 6)
然後只從 S 中選擇數字來進行多次投注
例如,對於 k = 8 和 S = {1, 2, 3, 5, 8, 13, 21, 34}
共有 28 種可能的投注組合:
[1,2,3,5,8,13]
[1,2,3,5,8,21]
[1,2,3,5,8,34]
[1,2,3,5,13,21]
...
[3,5,8,13,21,34]
你的任務是撰寫一個程式,讀入數字 k 和集合 S
然後列印出所有只從 S 中選擇數字的可能投注組合
輸入說明
輸入檔將包含一個或多個測試案例。
每個測試案例由一行多個以空格分隔的整數組成
該行的第一個整數是數字 k(6 < k < 13)
接下來的 k 個整數指定了集合 S,這些數字按升序排列
當 k 的值為零(0)時,表示輸入結束。
輸出說明
對於每個測試案例,列印出所有可能的投注組合,每個組合佔一行。
每個投注組合中的數字必須按升序排列,並且彼此之間以一個空格分隔
投注組合本身必須按字典順序排列,也就是首先按最小的數字排序,然後是第二小的數字,依此類推
各測試案例之間必須以一個空行分隔
在最後一個測試案例之後不要輸出空行
解題思路
從大小為 k(6 < k < 13)的已排序集合 v
中,列舉所有可能的 6 個數字子集合 ans
,並按字典序輸出
定義遞迴 f(x),表示是否考慮選取 v[x]
在每個位置做「選取」與「不選取」兩種決策
終止條件:
- 當已選數字數量達 6 → 輸出一組解並返回
- 當已考慮完所有元素但未選滿 6 個 → 返回
因為輸入的數字為已排序陣列,所以結果也會按照字典序輸出
程式碼
#include <bits/stdc++.h> using namespace std; vector<int> v, ans; void f(int x) { if (ans.size() == 6) { // 若 ans 陣列長度為 6,則進行輸出並終止 for (auto &i : ans) cout << i << " \n"[&i == &ans.back()]; return; } if (x == v.size()) return; // 若索引值超出 v 陣列的大小,就終止 ans.push_back(v[x]); // 選擇 v[x] f(x+1); // 往下枚舉 ans.pop_back(); // 不選擇 f(x+1); // 往下枚舉 } int main() { int n, T = 0; while (cin >> n, n) { if (T++) cout << '\n'; v.assign(n, 0); for (auto &i : v) cin >> i; f(0); } }