P5194 [USACO05DEC]Scales
阿新 • • 發佈:2022-04-12
這道題是一道搜尋題,一種思路是直接對每一個數做出選與不選的判斷,時間複雜度 \(O(2^n)\) 。在這種時間複雜度下,只能通過 \(n \leq 30\) 的資料。
如何進行優化呢?以下是我的優化:
- 改變搜尋順序。這一道題的輸入資料是一個不下降序列,如果我們把小的數放在前面,而 \(C\) 又比較大的話,前面的小數就會有很多的空間進行選擇,極限資料下甚至可以卡死程式碼。為了避免這種情況,我在讀入的時候從 \(a_n\) 開始倒著讀,這樣 a 陣列中就是一個不上升子序列,前面的大數很容易就因為 \(C\) 的限制失去很多選擇,節省了很多的時間。其中 a 陣列是我存放數的陣列。
- 模擬可行性剪枝,我們不妨這麼想:如果說當前所選的數的總和
在這些優化下,搜尋的複雜度會變得很低。當然,如果您有什麼更好的優化方法或剪枝,請私信我,感謝!
程式碼如下:
#include<bits/stdc++.h> using namespace std; const int MAXN=1000+10; int n,c,a[MAXN];//n c 如題 a 存放數 typedef long long LL; LL sum[MAXN],ans;//sum 字尾和 ans 答案 LL Max(LL fir,LL sec) { return (fir>sec)?fir:sec; } void dfs(int k,int now) { if(k>n)//選完了 { ans=Max((LL)now,ans); return; } if(now+sum[k]<=c)//優化2 { ans=Max(now+sum[k],ans); return; } if(now+a[k]<=c) dfs(k+1,now+a[k]); dfs(k+1,now); } int main() { scanf("%d %d",&n,&c); for(int i=n;i>=1;i--) scanf("%d",&a[i]);//優化1 for(int i=n;i>=1;i--) sum[i]=sum[i+1]+a[i]; dfs(1,0); printf("%lld\n",ans); return 0; }