日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【洛谷 - U43391】不是0-1背包的暴力AC(思维,二分,可转化为二元组问题,复习暴力dfs总结)

發布時間:2023/12/10 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【洛谷 - U43391】不是0-1背包的暴力AC(思维,二分,可转化为二元组问题,复习暴力dfs总结) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題干:

https://www.luogu.org/problemnew/show/U43391

自01背包問世之后,小A對此深感興趣。一天,小A去遠游,卻發現他的背包不同于01背包。 小A的背包最多能裝W的價值
現有n件物品,分別為v1,v2,v3……vn
問如何存放物品,使背包內物品總價值達到最大

輸入輸出格式

輸入格式:

?

輸入第一行包含兩個整數,分別代表n和W。 以后N行,每行一個正整數vi 表示第i個物品的價值 ?

?

輸出格式:

?

輸出僅一個整數,即最大價值。

?

輸入輸出樣例

輸入樣例#1:?復制

5 10 1 3 4 8 9

輸出樣例#1:?復制

10

說明

1 <= n <= 40
1 <= vi <= 1e7
1 <= w <= 1e9

解題報告:

? ?這題顯然是背包問題,但是就是沒法用背包做。直接暴力加點剪枝就可以過了,而且跑的很快,畢竟數據水、、并且題目說了是暴力AC。

? ?但是正解是什么呢?很玄學、、把n從中間分成兩份,然后答案就是三種情況:要么都在第一份,要么都在第二份,要么在第一份和第二份中各一個。很類似那道【CodeForces - 799C】Fountains? 的做法。這里給出syt學長的代碼。

暴力代碼:

#include<bits/stdc++.h> #define ll long long using namespace std; ll a[55]; int n,m,loc; ll ans = 0;void dfs(int x,ll cur) {if(x == loc) {ans = max(ans,cur);return;}ans = max(ans,cur);for(int i = x+1; i<=loc; i++) {if(cur+a[i] <= m)dfs(i,cur+a[i]);} } int main() {cin>>n>>m;for(int i = 1; i<=n; i++) scanf("%lld",a+i);sort(a+1,a+n+1);for(int i = 1; i<=n; i++) {loc = i;if(a[i] > m) break;}dfs(1,0);if(a[1] <= m)dfs(1,a[1]);printf("%lld\n",ans);return 0 ;}

其中dfs函數也可以這么寫:

void dfs(int x,ll cur) {//代表截止當前(x)位置,價值為cur的狀態。 ans = max(ans,cur);if(x == loc) return;for(int i = x+1; i<=loc; i++) {if(cur+a[i] <= m) dfs(i,cur+a[i]);} }

或者這樣:

void dfs(int x,ll cur) {if(x == loc) {ans = max(ans,cur);return;}if(cur+a[x+1] <= m)dfs(x+1,cur+a[x+1]);dfs(x+1,cur); }

其實這些代碼都是等價的,畫一個搜索樹就看出來了。但是剛開始寫也會寫崩、、反正還是沒理清楚到底表示的是什么狀態。?

AC代碼:

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e6+10;ll a[maxn],b[maxn]; ll v[50]; ll w; int pre[50]; int n;void init() {int i;pre[0]=1;for(i=1; i<=30; i++) pre[i]=2ll*pre[i-1];//2的n次方 }int main() {ll t,sum,ans;int i,j,k,l,r,m,p;init();scanf("%d%lld",&n,&w);for(i=1; i<=n; i++) scanf("%lld",&v[i]);ans=0;for(i=0; i<pre[n/2]; i++) {t=i,sum=0,j=n/2,k=1;while(j>0) {if(t%2) sum+=v[k];t/=2,j--,k++;}a[i]=sum;if(sum<=w) ans=max(ans,sum);}for(i=0; i<pre[n-n/2]; i++) {t=i,sum=0,j=n-n/2,k=n/2+1;while(j>0) {if(t%2) sum+=v[k];t/=2,j--,k++;}b[i]=sum;if(sum<=w) ans=max(ans,sum);}sort(b,b+pre[n-n/2]);/*printf("*%d %d*\n",pre[n/2],pre[n-n/2]);for(i=0;i<pre[n/2];i++) printf("%lld ",a[i]);printf("\n");for(i=0;i<pre[n-n/2];i++) printf("%lld ",b[i]);printf("\n");*/for(i=0; i<pre[n/2]; i++) {if(a[i]<w) {l=0,r=pre[n-n/2]-1,p=-1;m=(l+r+1)/2;while(l<r) {m=(l+r+1)/2;if(a[i]+b[m]<=w) l=m;else r=m-1;} // printf("l = %d\n",l);if(l!=0) ans=max(ans,a[i]+b[l]);}} // for(i=0; i<pre[n/2]; i++) { // if(a[i]<w) { // l=0,r=pre[n-n/2]-1,p=-1; // while(l<=r) { // m=(l+r)/2; // if(a[i]+b[m]<=w) l=m+1,p=m; // else r=m-1; // } // printf("p = %d\n",p); // if(p!=-1) ans=max(ans,a[i]+b[p]); // } // }printf("%lld\n",ans);return 0; }

騷操作:

#include<bits/stdc++.h> #define Mit map<int,bool>::iterator using namespace std; typedef long long ll; map<int,bool> M; vector<int> V; int main() {int n,w;scanf("%d%d",&n,&w);int x;for(int i=0;i<n;i++){scanf("%d",&x);V.clear();if(x<=w){V.push_back(x);for(Mit it=M.begin();it!=M.end()&&it->first<=w-x;it++){V.push_back(it->first+x);}for(int j=0;j<V.size();j++){M[V[j]]=true;}}}ll ans=0;Mit it=M.upper_bound(w);if(it!=M.begin()){it--;ans=it->first;}printf("%d\n",ans);return 0; }

?

總結

以上是生活随笔為你收集整理的【洛谷 - U43391】不是0-1背包的暴力AC(思维,二分,可转化为二元组问题,复习暴力dfs总结)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。