AcWing - 171 送礼物(双向dfs)
生活随笔
收集整理的這篇文章主要介紹了
AcWing - 171 送礼物(双向dfs)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目鏈接:點擊查看
題目大意:給出n個禮物,以及最大承重量,問在最大承重量內所搬的禮物最重是多少
題目分析:因為每個禮物只有搬或不搬兩種狀態,所以我們可以直接搜索,但是題目給出的N最大到了46,直接搜的話時間復雜度到了2的46次方,肯定會T,那么我們該怎么優化呢,這里用到了雙向搜索的技巧,先上定義:(摘自zx學長的ppt)
雙向搜索:
除了迭代加深以外,雙向搜索也可以避免在深層子樹上浪費時間。在一些題目中,問題不但具有初態,還具有明確的終態,并且從初態開始搜索與從終態開始逆向搜索產生的搜索樹都能覆蓋整個狀態空間。在這種情況下,就可以采取雙向搜索——從初態和終態出發各搜索一半狀態,產生兩棵深度減半的搜索樹,在中間交匯,組合成最終的答案。
?既然提到雙向,我們就可以直接將n除以二來對待,這樣一來時間復雜度瞬間下降到了2的23次方,差不多1e7不到,題目給了3秒可以應付,下面講一下大體思路
首先我們可以將禮物折半分成兩部分,用搜索先將第一部分的禮物可以組合的所有情況都搜出來,記錄下來并去重,然后開始搜另一部分的禮物,每次搜到盡頭時,用二分查找一下在不超過最大承重的范圍內,所能和當前結果組成的最大結果是多少,并實時更新答案,總的時間復雜度為,就可以完美解決這個問題了
再來說一下幾個可以優化剪枝的點吧:
代碼:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=50;LL n,w,ans;int cnt,limit;LL a[N],temp[(1<<25)+10];void dfs1(int pos,LL sum) {if(pos==limit){temp[cnt++]=sum;return;}if(sum+a[pos]<=w)dfs1(pos+1,sum+a[pos]);dfs1(pos+1,sum); }void dfs2(int pos,LL sum) {if(pos==n){int t=lower_bound(temp,temp+cnt,-(w-sum))-temp;ans=max(ans,sum-temp[t]);return;}if(sum+a[pos]<=w)dfs2(pos+1,sum+a[pos]);dfs2(pos+1,sum); }bool cmp(const LL& a,const LL& b) {return a>b; }int main() { // freopen("input.txt","r",stdin);while(scanf("%lld%lld",&w,&n)!=EOF){for(int i=0;i<n;i++)scanf("%lld",a+i);sort(a,a+n,cmp);limit=n/2+2;//選擇適當的折半點,算是一種剪枝cnt=0;dfs1(0,0);cnt=unique(temp,temp+cnt)-temp;for(int i=0;i<cnt;i++)temp[i]=-temp[i];sort(temp,temp+cnt);temp[cnt]=0;ans=0;dfs2(limit,0);printf("%lld\n",ans);}return 0; }?
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的AcWing - 171 送礼物(双向dfs)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 康托展开与逆展开(原理+模板)
- 下一篇: CodeForces - 363D Re