竞赛准备篇---(一)抽签问题
問題描述:
將寫有數字的 n個紙片放入口袋中,你可以從口袋中抽取 4次紙片,每次記下紙片上的數字后都將其放回口袋中。如果這 4個數字的和是 m,就是你贏,否則就是你的朋友贏。你挑戰了好幾回,結果一次也沒贏過,于是怒而撕破口袋,取出所有紙片,檢查自己是否真的有贏的可能性。請你編寫一個程序,判斷當紙片上所寫的數字是 k 1 ,k 2 , …, k n 時,是否存在抽取 4次和為 m的方案。如果存在,輸出 Yes;否則,輸出 No。
限制條件
? ?1 ≤ n ≤ 50
? ?1 ≤ m ≤ 108
? ?1 ≤ k i ≤108
輸入:
n = 3 ?? m = 10 ? k = {1, 3, 5}
輸出:
YES(1 + 1 + 3 + 5 = 10)
解題思路:
由于問題規模小,可以直接四重循環
?
拓展:
如果問題規模擴大,n屬于1到1000,上述算法肯定失效。所以必須優化算法:
最開始我們考慮的是檢查是否有ki,kj,kr,ks之和等于m,算法時間復雜度為O(n4)。轉移表達式,檢查是否存在ks = m - ki - kj - kr;可以想到,枚舉外面三層,最后判斷ks是否存在即可,判斷的話可以用二分查找,這樣時間復雜度降低成了O(n3log(n))。但是對于1000的數據還是需要很長的時間,所以考慮是否存在kr+ks = m - ki - kj。這種情況不能直接使用二分搜索,但是,如果事先枚舉出所有的kr + ks之和,并排序,就可以進行二分搜索。這樣預處理+排序+二重循環搜索時間復雜度降低成了O(n2log(n))。這樣n = 1000也可以輕易地過了。
1 #include<bits/stdc++.h> 2 #define FOR(i, a, b) for(int i = a; i < b; i++) 3 using namespace std; 4 const int maxn = 1e3 + 10; 5 int k[maxn]; 6 int kk[maxn * maxn]; 7 int tot; 8 int n, m; 9 bool binary_search(int x) 10 { 11 int l = 0, r = tot; 12 while(l <= r) 13 { 14 int m = (l + r) / 2; 15 if(kk[m] == x)return true; 16 if(kk [m] < x)l = m + 1; 17 else r = m - 1; 18 } 19 return false; 20 } 21 void init()//可以直接用STL里面的set,把兩層循環枚舉的和放入set中,直接判斷是否存在(set中的count函數) 22 { 23 for(int i = 0; i < n; i++) 24 { 25 for(int j = i; j < n; j++)kk[tot++] = k[i] + k[j]; 26 } 27 sort(kk, kk + tot);//排序 28 } 29 int main() 30 { 31 cin >> n >> m; 32 for(int i = 0; i < n; i++)cin >> k[i]; 33 init(); 34 bool ans = false; //標記是否找到解 35 FOR(i, 0, n)FOR(j, 0, n) 36 { 37 if(binary_search(m - k[i] - k[j]))ans = true; 38 } 39 if(ans)cout<<"YES"<<endl; 40 else cout<<"NO"<<endl; 41 }?
轉載于:https://www.cnblogs.com/fzl194/p/8666281.html
總結
以上是生活随笔為你收集整理的竞赛准备篇---(一)抽签问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot 添加 jsp支持
- 下一篇: 秋裤先别着急脱!“春捂”到底该“捂”哪儿