揹包dp(01)
阿新 • • 發佈:2020-07-04
01揹包
http://acm.hdu.edu.cn/showproblem.php?pid=2546
餘額為體積;
01揹包比較明顯;
因為是>=5時才能消費,所以預留5的空間,計算出在餘額為m-5的情況下,所能花費的最大價錢;
記住,因為只要>=5,不管菜多貴,都能買;所以我們希望5元時買的菜最貴;所以排序,只計算前n-1個菜獲得的最大值,再加上最後一個即可;
還有個特判m<5時
#include<bits/stdc++.h> using namespace std; #define int long long const int inf=0x7f7f7f; int t,n,m;int dp[1011],val[1010]; signed main() { while(scanf("%d",&n)!=EOF) { if(n==0) break; memset(val,0,sizeof(val)); for(int i=1;i<=n;i++) cin>>val[i]; memset(dp,0,sizeof(dp)); scanf("%d",&m); if(m<5) {cout<<m<<endl;continue;} sort(val+1,val+1+n); dp[0]=0; for(int i=1;i<=n-1;i++) { for(int j=m-5;j>=val[i];j--) { if(dp[j]<dp[j-val[i]]+val[i]){ dp[j]=dp[j-val[i]]+val[i]; } } } cout<<m-(dp[m-5]+val[n])<<endl; } }
間接求值
http://acm.hdu.edu.cn/showproblem.php?pid=2955
有小數,很明顯,p不能作為陣列下標的值;
如果搶劫銀行最多能搶x,對於搶這麼多錢x有個被抓的概率px;
只要px<=p即可;
而對於不被抓的概率,比較難算,因為不具獨立性;
比如兩個搶劫事件A,被抓概率PA=0.02,B,PB=0.03;
而被抓的概率=PA*(1-PB)+PB*(1-PA)+PA*PB
不被抓被抓的概率=(1-PA)*(1-PB);
所以dp【j】表示不被抓的概率
#include<bits/stdc++.h> using namespace std; #define int long long const int inf=0x3f; int t,n; int val[1010]; double pro[1010],dp[10101];//dp代表不被發現的概率 signed main() { cin>>t; while(t--) { double p; scanf("%lf %d",&p,&n); int sum=0; memset(dp,0,sizeof(dp)); memset(val,0,sizeof(val)); memset(pro,0,sizeof(pro)); for(int i=1;i<=n;i++) { scanf("%d %lf",&val[i],&pro[i]); sum+=val[i]; } dp[0]=1; for(int i=1;i<=n;i++) { for(int j=sum;j>=val[i];j--) dp[j]=max(dp[j],dp[j-val[i]]*(1.0-pro[i])); } for(int j=sum;j>=0;j--) { if(dp[j]>=(1.0-p)){ cout<<j<<endl;break; } } } }
揹包問題中求次優解,第K優解的問題
部落格:
https://blog.csdn.net/yandaoqiusheng/article/details/84782655
Bone Collector II
http://acm.hdu.edu.cn/showproblem.php?pid=2639
揹包又不是求最值,對於求k大值,dp[v][k]表示容量v時第k大值;
dp[j][k]可以由dp【j-v【i】】【h】+val【i】和dp[j][h]這兩個轉化過來;
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int inf=0x3f;
map<int,int> mp;
int t,n;
int val[1010],dp[1010][40],v[1010],a[1010],b[1010];
signed main()
{
cin>>t;
while(t--)
{
int n,m,k,sum=0;
cin>>n>>m>>k;
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++) cin>>val[i];
for(int i=1;i<=n;i++) cin>>v[i];
for(int i=1;i<=n;i++)
{
for(int j=m;j>=v[i];j--)
{
int l=1,r=1;
for(int h=1;h<=k;h++)
{
a[h]=dp[j][h];//a,b兩個陣列記錄所有可能的數值
b[h]=dp[j-v[i]][h]+val[i];
}
int p=1;
a[k+1]=-1,b[k+1]=-1;//合併兩個序列
while(p<=k&&(a[l]!=-1||b[r]!=-1)){//找出前k個
if(a[l]>b[r]) dp[j][p]=a[l],l++;
else dp[j][p]=b[r],r++;
if(dp[j][p]!=dp[j][p-1]) p++;
}
}
}
cout<<dp[m][k]<<endl;
}
}