AcWing 171. 送礼物
考察:双向搜索dfs
思路:
很像背包模型,但是用背包TLE.这道题N<=46,不能用背包就可以考虑搜索,如果普通的爆搜时间复杂度是O(2n),也会TLE,需要优化.爆搜常考虑的优化有迭代加深,但是W太大不考虑.还有就是双向dfs,适用于终态和初态明确的情况下.这道题的终态需要一点思维,我们将物品对半分,初态的dfs搜索前半部分,终态的dfs可以枚举后半部分的重量,然后找当前重量S+?<=W的最大值.数组里找符合某条件的最大值,多用于二分.这样的时间复杂度是223+223*log2223 = 223+223*23.为了压时间复杂度,我们可以把式子的左半部分放大一点,右边再乘一个数就可以和左边均衡.
总体思路确定,接下来考虑剪枝.很明显搜索顺序是从大到小.然后冗余情况考虑组合枚举.顺便这里进行set判重反而可能会TLE.用数组存储搜索完了再去重反而更快....
注意:int在计算时有爆掉风险
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <set> 5 using namespace std; 6 typedef long long LL; 7 const int N = 50,M = 25; 8 int w[N],m,n,k,weigh[(1<<M)+10],cnt,ans; 9 void dfs(int now,int idx) 10 { 11 if((LL)now+w[k]>m) return; 12 weigh[cnt++] = now; 13 for(int i=idx;i<=k;i++) 14 if((LL)w[i]+now<=m) dfs(now+w[i],i+1); 15 } 16 void dfs_2(int now,int st) 17 { 18 if((LL)now+weigh[1]>m) return; 19 int l = 0,r = cnt-1; 20 while(l<r) 21 { 22 int mid = l+r+1>>1; 23 if((LL)now+weigh[mid]<=m) l = mid; 24 else r = mid-1; 25 } 26 if((LL)now+weigh[r]>ans) ans = now+weigh[r]; 27 for(int i=st;i<=n;i++) 28 if((LL)w[i]+now<=m) dfs_2(now+w[i],i+1); 29 } 30 int main() 31 { 32 scanf("%d%d",&m,&n); 33 for(int i=1;i<=n;i++) scanf("%d",&w[i]); 34 sort(w+1,w+n+1); 35 reverse(w+1,w+n+1); 36 k = n/2+2; 37 dfs(0,1); 38 sort(weigh,weigh+cnt); 39 cnt = unique(weigh,weigh+cnt)-weigh; 40 dfs_2(0,k+1); 41 printf("%d\n",ans); 42 return 0; 43 }