抽簽問題(不斷優化)
阿新 • • 發佈:2018-01-28
得到 turn for () clas 判斷 spa 存在 alt
問題描述:
假設存在n個簽,通過抽取四次,如果四次抽取的和為m即勝利。
初始解:
1 for(int a = 0; a < n; a++) 2 { 3 for(int b = 0; b < n; b++) 4 { 5 for(int c = 0; c < n; c++) 6 { 7 for(int d = 0; d < n; d++) 8 { 9 if(k[a] + k[b] + k[c] + k[d] == m) 10 f = true; 11 } 12 } 13 } 14 }
難度增加,將n的限制條件為1~1000,此時,四重循環明顯復雜度過高,需改進算法。
上面所記載的程序的循環部分。最內側關於d的循環所做的事就是
檢查是否有d使得
通過對式子移項,就能得到另一種表達式
檢查是否有d使得
就是說,檢查數組k中所有元素,判斷是否有
結合二分搜索進行求解,註意二分搜索前提為該數組排好序(可用c++自帶的binary_serach)
1 int n, m, k[MAX_N]; 2 3 bool binary_serach(int x) 4 { 5 int l = 0, r = n; 6 while(r - 1 >= 1) 7 { 8 int i = (l + r) / 2; 9 if(k[i] == x) 10 return true; 11 else if(k[i] < x) 12 l = i + 1; 13 else 14 r = i; 15 } 16 return false; 17 } 18 19 void solve() 20 { 21 sort(k, k + n);22 bool f = false; 23 for(int a = 0; a < n; a++) 24 { 25 for(int b = 0; b < n; b++) 26 { 27 for(int c = 0; c < n; c++) 28 { 29 if(binary_serach(m - k[a] - k[b] - k[c])) 30 { 31 f = true; 32 } 33 } 34 } 35 } 36 if(f) 37 cout << "Yes" << endl; 38 else 39 cout << "No" << endl; 40 }
的算法
著眼於內層的兩個循環
檢查是否有c和d使得
這種情況並不能直接使用二分搜索。但是,如果預先枚舉出所得的個數字並排好序,便可以利用二分搜索了。
1 int n, m, k[MAX_N]; 2 int kk[MAX_N * MAX_N]; 3 bool binary_serach(int x) 4 { 5 int l = 0, r = n * n; 6 while(r - 1 >= 1) 7 { 8 int i = (l + r) / 2; 9 if(kk[i] == x) 10 return true; 11 else if(kk[i] < x) 12 l = i + 1; 13 else 14 r = i; 15 } 16 return false; 17 } 18 19 void solve() 20 { 21 for(int c = 0; c < n; c++) 22 { 23 for(int d = 0; d < n; d++) 24 { 25 kk[c * n + d] = k[c] + k[d]; 26 } 27 } 28 29 sort(kk, kk + n * n); 30 for(int a = 0; a < n; a++) 31 { 32 for(int b = 0; b < n; b++) 33 { 34 if(binary_serach(m - k[a] - k[b])) 35 { 36 f = true; 37 } 38 } 39 } 40 if(f) 41 cout << "Yes" << endl; 42 else 43 cout << "No" << endl; 44 }
抽簽問題(不斷優化)