标签:
1.混合了贪心思想的背包入门给定工作开始时间、完成时间、给的工资,工作不能重叠,求最大收益。
一维Dp表示截止到当前时间的最大收益,但是事先要对结构体按结束时间排序,防止前一状态没有值
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; int dp[1005]; struct money { int l,r,w; }a[1005]; int cmp(money x,money y)//排序都快忘了怎么写了= = { if(x.r==y.r) return x.l<y.l; return x.r<y.r; } int main() { // freopen("cin.txt","r",stdin); int n,t,m; scanf("%d",&t); while(t--) { memset(dp,0,sizeof(dp)); scanf("%d%d",&m,&n);//假期时间m和可做的工作数n for(int i=1;i<=n;i++) scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].w); sort(a+1,a+1+n,cmp); for(int i=1;i<=n;i++) { for(int j=m;j>=a[i].r;j--) { dp[j]=max(dp[j],dp[j]-(dp[a[i].r]-dp[a[i].l-1])+a[i].w);//重点的重点 } } printf("%d\n",dp[m]); } }
#include <iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> using namespace std; int price[50500],f[50500],n,t,sum; int dp() { memset(f,0,sizeof(f)); for(int i=1;i<=n;i++) { for(int j=sum;j>=price[i];j--) { if(f[j]<f[j-price[i]]+price[i]) f[j]=f[j-price[i]]+price[i]; } } return f[sum]; } int main() { // freopen("cin.txt","r",stdin); while(~scanf("%d",&t)) { while(t--) { scanf("%d",&n); sum=0; for(int i=1;i<=n;i++) { scanf("%d",&price[i]); sum+=price[i]; } int cnt=sum; sum=(sum+1)/2; cnt=dp()*2-cnt; if(cnt<0) cnt=-cnt; printf("%d\n",cnt); } } return 0; }
#include <iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; double pj[1050],dp[100500],p,rate; int t,m[1050],n,sum; double max(double a,double b) { if(a<b) return b; else return a; } int main() { // freopen("cin.txt","r",stdin); while(~scanf("%d",&t)) { while(t--) { memset(dp,0,sizeof(dp)); dp[0]=1; sum=0; scanf("%lf%d",&p,&n); p=1-p; for(int i=0;i<n;i++) { scanf("%d%lf",&m[i],&pj[i]); pj[i]=1-pj[i]; sum+=m[i]; } for(int i=0;i<n;i++) { for(int j=sum;j>=m[i];j--) dp[j]=max(dp[j],dp[j-m[i]]*pj[i]); } for(int i=sum;i>=0;i--) { if(dp[i]>p) { printf("%d\n",i); break; } } } } return 0; }
#include <iostream> #include<cstring> #include<cstdio> using namespace std; int dp[2005],cost[2005],a[2005],b[2005]; int main() { //freopen("cin.txt","r",stdin); int t,m,n; while(cin>>t) { while(t--) { cin>>m>>n; memset(dp,0,sizeof(dp)); for(int i=0;i<n;i++) cin>>cost[i]>>a[i]>>b[i]; for(int i=0;i<n;i++) { for(int j=m;j>=cost[i];j--) if(dp[j]<dp[j-cost[i]]+a[i]+b[i]) dp[j]=dp[j-cost[i]]+a[i]+b[i]; for(int j=cost[i];j<=m;j++) if(dp[j]<dp[j-cost[i]]+a[i]) dp[j]=dp[j-cost[i]]+a[i]; } cout<<dp[m]<<endl; } } return 0; }
#include <iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; int n; int price[1005],f[1005]; int m; int main() { //freopen("data.in.txt","r",stdin); while(~scanf("%d",&n)&&n) { for(int i=1;i<=n;i++) scanf("%d",&price[i]); scanf("%d",&m); f[0]=0; //for(int i=1;i<=n;i++) f[i]=-999999; memset(f,0,sizeof(f)); sort(price+1,price+n+1); for(int i=1;i<=n-1;i++) { for(int v=m-5;v>=price[i];v--) f[v]=max(f[v],f[v-price[i]]+price[i]); } if(m>=5) printf("%d\n",m-f[m-5]-price[n]); else printf("%d\n",m); } return 0; }
#include <iostream> #include<cstdio> #include<cstring> //#define INF 0x7ffffff using namespace std; int cost[1005]; int price[1005]; int f[1005]; int main() { int m,t; while(~scanf("%d%d",&t,&m)) { f[0]=0; memset(f,0,sizeof(f)); //for(int i=1;i<=m;i++) f[i]=-999999; for(int i=1;i<=m;i++) scanf("%d%d",&cost[i],&price[i]); for(int i=1;i<=m;i++) { for(int v=t;v>=cost[i];v--) f[v]=max(f[v],f[v-cost[i]]+price[i]); } printf("%d\n",f[t]); } return 0; }
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[50005]; int value[60],num[60]; int n,total,sum; void zero(int cost,int weight) { for(int i=total;i>=cost;i--) dp[i]=max(dp[i],dp[i-cost]+weight); } void complete(int cost,int weight) { for(int i=cost;i<=cost;i++) dp[i]=max(dp[i],dp[i-cost]+weight); } void multi(int cost,int weight,int cnt) { if(total<=cnt*cost) { complete(cost,weight); return; } int k=1; while(k<=cnt) { zero(k*cnt,k*weight); cnt=cnt-k; k=2*k; } zero(cnt*cost,cnt*weight); } int main() { while(~scanf("%d",&n)) { if(n==-1) break; total=0; sum=0; for(int i=0;i<n;i++) { scanf("%d%d",&value[i],&num[i]); total+=(value[i]*num[i]); } printf("%d \n",total); sum=total; total/=2; memset(dp,0,sizeof(dp)); for(int i=0;i<n;i++) { multi(value[i],value[i],num[i]); } printf("%d %d\n",sum-dp[total],dp[total]); } return 0; }也可以用01背包搞 就是把相同价值的一种看成是多件
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,tot,a,b,sum; int dp[255000],val[600]; int main() { while(~scanf("%d",&n),n>0) { sum=0; tot=0; for(int i=0;i<n;i++) { scanf("%d%d",&a,&b); while(b--) { val[tot++]=a; sum+=a; } } memset(dp,0,sizeof(dp)); for(int i=0;i<tot;i++) { for(int j=sum/2;j>=val[i];j--) { dp[j]=max(dp[j],dp[j-val[i]]+val[i]); } } printf("%d %d\n",sum-dp[sum/2],dp[sum/2]); } return 0; }
作为一个正常的背包,我们必须做的两重循环是一定要写的,接下来就是维护最优解到第k优解的的数组。个人觉得这个题最最值得学习的就是维护数组的写法:
首先每次想加入新物品的时候,正常来说我们有两个值:之前的dp和加入新物品时的值,然而我们现在也需要考虑第k优解的问题,所以用两个临时的数组倒一下,再用这两个数组合并到一起存储到最终的dp数组中
/************ hdu2639 2015.10.20 109MS 5548K 1226B ************/ #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[1009][1009]; int value[109],cost[109]; int n,k,v,t; int a[1009],b[1009]; int main() { while(~scanf("%d",&t)) { while(t--) { scanf("%d%d%d",&n,&v,&k); for(int i=1;i<=n;i++) scanf("%d",&value[i]); for(int i=1;i<=n;i++) scanf("%d",&cost[i]); memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) for(int j=v;j>=cost[i];j--) { for(int m=1;m<=k;m++) { a[m]=dp[j][m]; b[m]=dp[j-cost[i]][m]+value[i]; } int x=1,y=1,w=1; a[k+1]=-1;b[k+1]=-1; while((w<=k)&&(x<=k||y<=k)) { if(a[x]<b[y]) dp[j][w]=b[y++]; else dp[j][w]=a[x++]; if(w==1||dp[j][w-1]!=dp[j][w]) w++; } } printf("%d\n",dp[v][k]); } } return 0; }
#include<stdio.h> #include<algorithm> #include<iostream> using namespace std; const int MAXN=5005; int dp[MAXN]; struct Node { int p,q,v; }node[505]; bool cmp(Node a,Node b) { return (a.q-a.p)<(b.q-b.p); } int main() { int n,m; int i,j; int p,q,v; while(scanf("%d%d",&n,&m)!=EOF) { for(i=0;i<=m;i++) dp[i]=0; for(i=0;i<n;i++) { scanf("%d%d%d",&node[i].p,&node[i].q,&node[i].v); } sort(node,node+n,cmp); for(i=0;i<n;i++) { for(j=m;j>=node[i].p;j--) { if(j>=node[i].q) dp[j]=max(dp[j],dp[j-node[i].p]+node[i].v); } } int ans=0; for(i=1;i<=m;i++) if(ans<dp[i]) ans=dp[i]; printf("%d\n",ans); } return 0; }
#include<stdio.h> #include<algorithm> #include<iostream> #include<cstring> using namespace std; const int MAXN=4000009; int dp[MAXN]; struct Node { int p,q,v; }node[35]; bool cmp(Node a,Node b) { return (a.q-a.p)<(b.q-b.p); } int main() { // freopen("cin.txt","r",stdin); int n,w; int i,j; int p,q,v; while(scanf("%d%d",&n,&w)!=EOF) { memset(dp,0,sizeof(dp)); int sum=0,up=0; for(i=0;i<n;i++) { scanf("%d%d%d",&node[i].p,&node[i].v,&node[i].q); sum+=node[i].p; up=max(up,node[i].q); } up=max(up,sum); sort(node,node+n,cmp); for(i=0;i<n;i++) { for(j=up;j>=node[i].p;j--) { if(j>=node[i].q) dp[j]=max(dp[j],dp[j-node[i].p]+node[i].v); } } int ans=0; for(i=1;i<=up;i++) if(w<=dp[i]) {ans=i;break;} if(ans) printf("%d\n",ans); else puts("zhx is naive!"); } return 0; } <span style="font-size:14px;"> </span>9.负数处理+两个总和的和最大
虽然N只有100,但是也不可以逐个枚举啊,可以选取两个值中的一个作为背包容量,另一个作为总价值。负数的处理是另外与价值数组更新时维护一个数组表示当前数组内的元素,因为+1000了嘛,要记着加了几个。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <iostream> #include <algorithm> #include <map> #define LL long long using namespace std; const int N = 110; const int M = 200010; const int NN = 1000; const int INF = 10000000; int w[N],v[N],sum; int dp[M], cnt[M]; int main() { // freopen("1.txt","r",stdin); int n; while(~scanf("%d",&n)) { sum=0; for(int i=1;i<=n;i++) { scanf("%d%d",&v[i],&w[i]); if(v[i]<0&&w[i]<0){i--,n--;continue;} v[i]+=1000; sum+=v[i]; } memset(dp,-0x3f3f3f3f,sizeof(dp)); dp[0]=0; memset(cnt,0,sizeof(cnt)); for(int i=1;i<=n;i++) { for(int j=sum;j>=v[i];j--) { if(dp[j-v[i]]+w[i]-(cnt[j-v[i]]+1)*1000>dp[j]-cnt[j]*1000) { cnt[j]=cnt[j-v[i]]+1; dp[j]=dp[j-v[i]]+w[i]; } } } int ans=0; for(int i=0;i<=sum;i++) { if(i-cnt[i]*1000>0&&dp[i]>0)// { ans=max(ans,dp[i]-cnt[i]*1000+i); } } printf("%d\n",ans); } return 0; }
既然是二维背包那么二维分别是现有忍耐度和打怪的个数
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[105][105],k,n,m,s,a[105],b[105]; int main() { // freopen("cin.txt","r",stdin); while(~scanf("%d%d%d%d",&n,&m,&k,&s)) { for(int i=1;i<=k;i++) scanf("%d%d",&a[i],&b[i]); // memset(f,0,sizeof(f)); memset(dp,0,sizeof(dp)); for(int i=1;i<=k;i++) { for(int j=b[i];j<=m;j++) { for(int l=1;l<=s;l++) { dp[j][l]=max(dp[j][l],dp[j-b[i]][l-1]+a[i]); } } } int flag=0; for(int i=1;i<=m;i++) { for(int j=1;j<=s;j++) { if(dp[i][j]>=n) { printf("%d\n",m-i); flag=1; goto loop; } } } loop : if(!flag) printf("-1\n"); } return 0; }
/************* hdu3127 2015.10.27-2015.10.29 296MS 5536K 1130 B ************/ #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,X,Y,t; int dp[1005][1005],x[12],y[12],c[12]; int max(int a,int b,int c) { if(a>b) { if(c>a) return c; return a; } if(c>b) return c; return b; } int main() { //freopen("cin.txt","r",stdin); cin>>t; while(t--) { cin>>n>>X>>Y; for(int i=1;i<=n;i++) cin>>x[i]>>y[i]>>c[i]; memset(dp,0,sizeof(dp)); for(int k=1;k<=n;k++) { for(int i=0;i<=X;i++) { for(int j=0;j<=Y;j++) { if(i>=x[k]&&j>=y[k]) dp[i][j]=max(dp[i][j],dp[i-x[k]][j]+dp[x[k]][j-y[k]]+c[k],dp[i][j-y[k]]+dp[i-x[k]][y[k]]+c[k]); if(i>=y[k]&&j>=x[k]) dp[i][j]=max(dp[i][j],dp[i-y[k]][j]+dp[y[k]][j-x[k]]+c[k],dp[i][j-x[k]]+dp[i-y[k]][x[k]]+c[k]); } } } cout<<dp[X][Y]<<endl; } return 0; }
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[10005],t,n; int value[4]={0,150,200,350}; int main() { scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=1;i<=n;i++) dp[i]=0; for(int i=1;i<=3;i++) for(int j=value[i];j<=n;j++) { dp[j]=max(dp[j-value[i]]+value[i],dp[j]); } printf("%d\n",n-dp[n]); } return 0; }
#include <iostream> #include<cstdio> #include<cstring> using namespace std; int dp[1050],c[1050],w[1050],m[1050]; int n,M,t; void zeropack(int cost,int weight) { for(int i=n;i>=cost;i--) dp[i]=max(dp[i-cost]+weight,dp[i]); } void completepack(int cost,int weight) { for(int i=cost;i<=n;i++) dp[i]=max(dp[i-cost]+weight,dp[i]); } void multipack(int cost,int weight,int num) { if(num*cost>=n) { completepack(cost,weight); return; } int k=1; while(k<num) { zeropack(k*cost,k*weight); num-=k; k*=2; } zeropack(cost*num,weight*num); } int main() { scanf("%d",&t); while(t--) { scanf("%d%d",&n,&M); for(int i=1;i<=M;i++) scanf("%d%d%d",&c[i],&w[i],&m[i]); memset(dp,0,sizeof(dp)); for(int i=1;i<=M;i++) { multipack(c[i],w[i],m[i]); } printf("%d\n",dp[n]); } return 0; }
#include <iostream> #include<cstdio> #include<cstring> using namespace std; int dp[100007],n,m,a[105],c[105],count; void zeropack(int cost,int value) { for(int i=m;i>=cost;i--) dp[i]=max(dp[i],dp[i-cost]+value); // cout<<"01"<<endl; } void completepack(int cost,int value) { for(int i=cost;i<=m;i++) dp[i]=max(dp[i],dp[i-cost]+value); //cout<<"complete"<<endl; } void multipack(int cost,int value,int num) { if(num*cost>=m) { completepack(cost,value); return; } int k=1; while(k<num) { zeropack(k*cost,k*value); num-=k; k*=2; } zeropack(num*cost,num*value); } int main() { // freopen("cin.txt","r",stdin); while(~scanf("%d%d",&n,&m)) { if(n==0&&m==0) break; for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&c[i]); memset(dp,0,sizeof(dp)); count=0; for(int i=1;i<=n;i++) { multipack(a[i],a[i],c[i]); } for(int i=1;i<=m;i++) { if(dp[i]==i) count++; //printf("dp[]=%d\n",dp[i]); } printf("%d\n",count); } return 0; }
#include <iostream> #include<cstdio> #include<cstring> using namespace std; int dp[90000],value[10],cost[10],num[10],v; void zeropack(int cost,int value) { for(int i=v;i>=cost;i--) dp[i]=max(dp[i],dp[i-cost]+value); // printf("zero "); } void complete(int cost,int value) { for(int i=cost;i<=v;i++) dp[i]=max(dp[i],dp[i-cost]+value); //printf("complete "); } void multipack(int cost,int value,int num) { if(num==0) return; if(cost*num>=v) { complete(cost,value); return; } int k=1; while(k<num) { zeropack(k*cost,k*value); num-=k; k*=2; } zeropack(num*cost,num*value); } int main() { //freopen("cin.txt","r",stdin); int cnt=1; while(~scanf("%d%d%d%d%d%d",&num[1],&num[2],&num[3],&num[4],&num[5],&num[6])) { for(int i=1;i<=6;i++) value[i]=i; for(int i=1;i<=6;i++) cost[i]=i; if(num[1]==0&&num[2]==0&&num[3]==0&&num[4]==0&&num[5]==0&&num[6]==0) break; v=num[1]+num[2]*2+num[3]*3+num[4]*4+num[5]*5+num[6]*6; //for(int i=1;i<=6;i++) if(!num[i]) {value[i]=0;cost[i]=0;} //for(int i=1;i<=6;i++) printf("%d ",num[i]); if(v&1) { printf("Collection #%d:\nCan't be divided.\n\n",cnt++); continue; } v/=2; memset(dp,0,sizeof(dp)); for(int i=1;i<=6;i++) { if(num[i]==0) continue; //printf("i=%d ",i); multipack(cost[i],value[i],num[i]); // printf("i=%d ",i); // for(int j=cost[i];j<=v;j++)printf("i=%d j=%d dp[j]=%d ",i,j,dp[j]); // printf("\n"); } //printf("%d\n",dp[v]); // for(int i=1;i<=6;i++) printf("%d ",dp[i]); if(dp[v]!=v) printf("Collection #%d:\nCan't be divided.\n\n",cnt++); else printf("Collection #%d:\nCan be divided.\n\n",cnt++); } return 0; }
#include <iostream> #include<cstdio> #include<cstring> using namespace std; #define maxn 20000 int dp1[maxn+6],value[105],num[105],t,n,dp2[maxn+6];//钱币个数 int f1[maxn+6],f2[maxn+6];//钱数 void zeropack(int cost,int value,int k) { for(int i=maxn;i>=cost;i--) { if(dp1[i-cost]!=-1&&(dp1[i-cost]+k<dp1[i]||dp1[i]==-1)) dp1[i]=dp1[i-cost]+k; } // cout<<"01"<<endl; } void completepack(int cost,int value) { for(int i=cost;i<=maxn;i++) { if(dp1[i-cost]!=-1&&(dp1[i-cost]+1<dp1[i]||dp1[i]==-1)) dp1[i]=dp1[i-cost]+1; // f1[i]=max(f1[i],f1[i-cost]+value); } //cout<<"complete"<<endl; } void multipack(int cost,int value,int num) { if(num*cost>=maxn) { completepack(cost,value); return; } int k=1; while(k<num) { zeropack(k*cost,k*value,k); num-=k; k*=2; } zeropack(num*cost,num*value,k); } int main() { // freopen("cin.txt","r",stdin); int cnt=1; while(~scanf("%d%d",&n,&t)) { if(t==0&&n==0) break; for(int i=1;i<=n;i++) scanf("%d",&value[i]); for(int i=1;i<=n;i++) scanf("%d",&num[i]); memset(dp2,-1,sizeof(dp2)); memset(dp1,-1,sizeof(dp1)); memset(f1,0,sizeof(f1)); memset(f2,0,sizeof(f2)); dp2[0]=0;dp1[0]=0; for(int i=1;i<=n;i++) for(int j=value[i];j<=maxn;j++) { if(dp2[j-value[i]]!=-1&&(dp2[j]<dp2[j-value[i]]+1||dp2[j]==-1)) dp2[j]=dp2[j-value[i]]+1; // f2[j]=max(f2[j],f2[j-value[i]]+value[i]); } for(int i=1;i<=n;i++) { multipack(value[i],value[i],num[i]); } // for(int i=70;i<=80;i++) printf("f1=%d f2=%d dp1=%d dp2=%d\n",f1[i],f2[i],dp1[i],dp2[i]); int minn=0x3f3f3f3f; for(int i=t;i<=maxn;i++) { //if(f1[i]!=i||f2[i-t]!=i-t) continue; if(dp1[i]!=-1&&dp2[i-t]!=-1) minn=min(minn,dp1[i]+dp2[i-t]); } if(minn!=0x3f3f3f3f) printf("Case %d: %d\n",cnt++,minn); else printf("Case %d: -1\n",cnt++); } return 0; }
这是一道综合性的背包问题。题目给出了多组工作,每组工作的选择规则不同,有些组至少要选一项,有些组最多选一项,有些组任意选。 这道题花了很长时间,需要深入理解状态转移才能够明白。数组dp[i][j],表示第i组,时间剩余为j时的快乐值。每得到一组工作就进行一次DP,所以dp[i]为第i组的结果。下面对三种情况进行讨论。 第一类,至少选一项,即必须要选,那么在开始时,对于这一组的dp的初值,应该全部赋为负无穷,这样才能保证不会出现都不选的情况。状态转移方程为dp[i][k]=max{ dp[i][k],dp[i-1][k-cost[j]]+val[k],dp[i][k-cost[j]]+val[j] }。dp[i][k]是不选择当前工作;dp[i-1][k-cost[j]]+val[k]是选择当前工作,但是是第一次在本组中选,由于开始将该组dp赋为了负无穷,所以第一次取时,必须由上一组的结果推知,这样才能保证得到全局最优解;dp[i][k-cost[j]]+val[j]表示选择当前工作,并且不是第一次取。 第二类,最多选一项,即要么不选,一旦选,只能是第一次选。所以状态转移方程为dp[i][k]=max{ dp[i][k],dp[i-1][k-cost[j]]+val[k]}。由于要保证得到全局最优解,所以在该组DP开始以前,应该将上一组的DP结果先复制到这一组的dp[i]数组里,因为这一组的数据是在上一组数据的基础上进行更新的。 第三类,任意选,即不论选不选,选几次都可以,显然状态转移方程为dp[i][k]=max{ dp[i][k],dp[i-1][k-cost[j]]+val[k],dp[i][k-cost[j]]+val[j] }。同样要保证为得到全局最优解,先复制上一组解。
#include<stdio.h> #include<string.h> #define INF 1000000 #define MAX_LIMT 110 int get_max(int,int); int main() { int n,t; while(scanf("%d%d",&n,&t)!=EOF) { int i,j,k,dp[MAX_LIMT][MAX_LIMT]; memset(dp,0,sizeof(dp)); for(i=1;i<=n;i++) { int m,s,cost[MAX_LIMT],val[MAX_LIMT]; scanf("%d%d",&m,&s); for(j=1;j<=m;j++) { scanf("%d%d",&cost[j],&val[j]); } if(s==0) { for(j=0;j<=t;j++) { dp[i][j]=-INF; } for(j=1;j<=m;j++) { for(k=t;k>=cost[j];k--) { dp[i][k]=get_max( dp[i][k],dp[i][k-cost[j]]+val[j]); dp[i][k]=get_max( dp[i][k],dp[i-1][k-cost[j]]+val[j]); } } } else if(s==1) { for(j=0;j<=t;j++) { dp[i][j]=dp[i-1][j]; } for(j=1;j<=m;j++) { for(k=t;k>=cost[j];k--) { dp[i][k]=get_max(dp[i][k],dp[i-1][k-cost[j]]+val[j]); } } } else { for(j=0;j<=t;j++) { dp[i][j]=dp[i-1][j]; } for(j=1;j<=m;j++) { for(k=t;k>=cost[j];k--) { dp[i][k]=get_max( dp[i][k],dp[i][k-cost[j]]+val[j]); dp[i][k]=get_max( dp[i][k],dp[i-1][k-cost[j]]+val[j]); } } } } dp[n][t]=get_max(dp[n][t],-1); printf("%d\n",dp[n][t]); } return 0; } int get_max(int x,int y) { return x>y?x:y; }
求最终能有最多多少白色格子。
由于题中没说到底涂哪些,我们认为都是连着涂的,那么我们就可以将给出的数据转化成可涂的长度,分别用两个数组计算当前长度范围最多可涂个数的最少次数,求和取最小值即可
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <vector> #include <cmath> using namespace std; const int maxn = 2005; struct node{ int aa,cor; node(){} node(int _aa,int _cor){ aa = _aa; cor = _cor; } }x1[maxn],x2[maxn]; int n,m; int dp1[maxn],dp2[maxn]; int sumx1,sumx2; bool cmp(const node &p,const node &q){ return p.aa < q.aa; } int min(int a,int b) { return a<b?a:b; } int main() { int cas,ta=1; scanf("%d",&cas); while(cas--){ int i,j; scanf("%d%d",&n,&m); sumx1 = sumx2 = 1; for(i=0; i<m; i++){ int key,yy,z; scanf("%d%d%d",&key,&yy,&z); if(key == 1){ x1[sumx1++] = node(yy,z); }else{ x2[sumx2++] = node(n+1-yy,z); } } sort(x1+1,x1+sumx1,cmp); sort(x2+1,x2+sumx2,cmp); memset(dp1,0x3f,sizeof(dp1)); memset(dp2,0x3f,sizeof(dp2)); dp1[0] = dp2[0] = 0; for(i=1; i<sumx1; i++){ for(j=x1[i].aa; j>=x1[i].cor; j--){ dp1[j] = min(dp1[j],dp1[j-x1[i].cor]+1); } } for(i=1; i<sumx2; i++){ for(j=x2[i].aa; j>=x2[i].cor; j--){ dp2[j] = min(dp2[j],dp2[j-x2[i].cor]+1); } } int ans = 0,anssum = 0,tmp; for(i=1; i<=n; i++){ for(j=0; j<=i; j++){ tmp = dp1[j] + dp2[i-j]; if(tmp <= m){ if(ans != i){ ans = i; anssum = tmp; }else if(tmp < anssum){ anssum = tmp; } } } } printf("Case %d: %d %d\n",ta++,ans,anssum); } return 0; }
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[40004]; int n,M,t; struct node { int cost,weight,num,height; }num[300]; bool cmp(node a,node b) { return a.height<b.height; } void zeropack(int cost,int weight,int height) { for(int i=height;i>=cost;i--) dp[i]=max(dp[i-cost]+weight,dp[i]); } void completepack(int cost,int weight,int height) { for(int i=cost;i<=height;i++) dp[i]=max(dp[i-cost]+weight,dp[i]); } void multipack(int cost,int weight,int num,int height) { if(num*cost>=height) { completepack(cost,weight,height); return; } int k=1; while(k<num) { zeropack(k*cost,k*weight,height); num-=k; k*=2; } zeropack(cost*num,weight*num,height); } int main() { // freopen("cin.txt","r",stdin); while(~scanf("%d",&n)) { int maxn=0; for(int i=1;i<=n;i++) { scanf("%d%d%d",&num[i].cost,&num[i].height,&num[i].num); num[i].weight=num[i].cost; if(maxn<num[i].height) maxn=num[i].height; } sort(num+1,num+1+n,cmp); // printf("hei=%d ",maxn); memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) multipack(num[i].cost,num[i].weight,num[i].num,num[i].height); int tmp=0; for(int i=1;i<=maxn;i++) { if(tmp<dp[i]) tmp=dp[i]; //printf("%d ",dp[i]); } printf("%d\n",tmp); } return 0; }
#include <iostream> #include<cstdio> #include<cstring> using namespace std; int num[110][110],n,m; int dp[110]; int max(int a,int b){if(a>b)return a;return b;} int main() { // freopen("cin.txt","r",stdin); while(~scanf("%d%d",&n,&m)) { if(m==0&&n==0)break; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&num[i][j]); memset(dp,0,sizeof(dp)); for(int k=1;k<=n;k++)//the type of course for(int v=m;v>=0;v--) for(int j=1;j<=v;j++) dp[v]=max(dp[v],dp[v-j]+num[k][j]); printf("%d\n",dp[m]); } return 0; }21.分组背包每组至少去取一个
由于限制了每组个数,我们需要加一维表示组别,而且前一状态不可没被填充
/*********** hdu3033 2016.3.13 93MS 5888K 1238B G++ ***********/ #include <iostream> #include<cstdio> #include<cstring> using namespace std; struct node { int u,v; }g[15][110]; int num[15],dp[110][10005]; int n,m,k,a,b,c; int max(int a,int b){if(a>b)return a;return b;} #define inf 0x3f3f3f3f int main() { while(~scanf("%d%d%d",&n,&m,&k)) { memset(num,0,sizeof(num)); for(int i=1;i<=n;i++) { scanf("%d%d%d",&a,&b,&c); num[a]++; g[a][num[a]].u=b; g[a][num[a]].v=c; } memset(dp,-inf,sizeof(dp)); //有的时候memset赋值-inf会出错 memset(dp[0],0,sizeof(dp[0])); for(int i=1;i<=k;i++) { for(int j=1;j<=num[i];j++) { for(int v=m;v>=g[i][j].u;v--) { //if(dp[i][v-g[i][j].u]!=-1) dp[i][v]=max(dp[i][v],dp[i][v-g[i][j].u]+g[i][j].v); //if(dp[i-1][v-g[i][j].u]!=-1) dp[i][v]=max(dp[i][v],dp[i-1][v-g[i][j].u]+g[i][j].v); } } } if(dp[k][m]<0)printf("Impossible\n"); else printf("%d\n",dp[k][m]); } return 0; }22.
小姑娘开学前晚上看电影只能L分钟,有N个不同的电影可以选择,傲娇老板只恰好卖M张蝶,给出每部电影时长和快乐值,问最大的快乐值是多少
组别是n种电影,组内是电影的个数,dp一维表示电影个数,二维表示时间长度
#include <iostream> #include<cstdio> #include<cstring> using namespace std; #define inf 0x3f3f3f3f int dp[102][1005],cost[102],value[102],t,n,m,l; int max(int a,int b){if(a>b)return a;return b;} int main() { // freopen("cin.txt","r",stdin); scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m,&l); for(int i=1;i<=n;i++)scanf("%d%d",&cost[i],&value[i]); for(int i=0;i<=m;i++) for(int j=0;j<=l;j++) dp[i][j]=-0x3f3f3f3f; dp[m][l]=dp[0][0]=0; for(int i=1;i<=n;i++) for(int j=m;j>0;j--) for(int k=cost[i];k<=l;k++) dp[j][k]=max(dp[j][k],dp[j-1][k-cost[i]]+value[i]);//printf("i=%d,j=%d,k=%d,dp=%d\n",i,j,k,dp[j][k]); for(int i=0;i<l;i++)dp[m][l]=max(dp[m][l],dp[m][i]) ; printf("%d\n",dp[m][l]); } return 0; }
23.01背包方法数使得是剩下的钱数不能大于没买的物品的最小值
//思路:先对n个体积进行从小到大的排序,然后枚举i作为剩余物品中体积最小为v,dp[j]为方案数(其中j为当前体积).那么可以分析对于大于i的, //很显然是可以放进背包的,又因为i为剩余的物品,所以不放进去;对于大于i的物品则进行背包的可行方案的统计.然后计算{Fn[j]}之和。 #include <stdio.h> #include <string.h> #include <stdlib.h> #define M 10000 #define max(a, b) (a > b ? a : b) int data[M], dp[M]; int n, c; int cmp(const void *a, const void *b) { return *(int *)a - *(int *)b; } int main() { //freopen("1.txt", "r", stdin); int i, j, k, test, sum, ans, num = 1; scanf("%d", &test); while (test--) { scanf("%d%d", &n, &c); for (i = 1; i <= n; i++) { scanf("%d", &data[i]); } qsort(data + 1, n, sizeof(data[1]), cmp); memset(dp, 0, sizeof(dp)); for (i = 1, sum = 0, ans = 0; i <= n; i++) { memset(dp, 0, sizeof(dp)); dp[sum] = 1; for (j = i + 1; j <= n; j++) { for (k = c; k >= data[j] + sum; k--) { dp[k] += dp[k - data[j]]; } } for (j = c; j >= max(c - data[i] + 1, 1); j--) //c-data[i]+1 其中+1是因为下标以1开始 { if (j >= sum) { ans += dp[j]; } } sum += data[i]; } printf("%d %d\n", num++, ans); } return 0; }24.
题意:给女朋友买一堆礼物,每个礼物有一个快乐值,有n个备选的,其中有一部分是必买的,总共有两张支票,价值v1,v2,花钱少了不给退,两张支票不能凑在一起用,而且有一个礼物是免费的,问女友最多可以多快乐?
做法:这个题的处理方法是再加一维dp表示是否用过这个免费的机会(貌似之前树形dp做过吧)之后,dp转移是很容易可以想到的==
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int cost1[309],hap1[309],cost0[309],hap0[309],dp[505][55][2],n,v1,v2; int main() { // freopen("cin.txt","r",stdin); //freopen("out.txt","w",stdout); int cas=1; while(~scanf("%d%d%d",&v1,&v2,&n)) { if(v1==0&&v2==0&&n==0)break; memset(dp,0,sizeof(dp)); int l0=0,l1=0,maxh=0,maxn; for(int i=0;i<n;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); if(c==1) { cost1[l1]=a; hap1[l1++]=b; maxh+=b; } if(c==0) { cost0[l0]=a; hap0[l0++]=b; } } for(int i=0;i<l1;i++) { for(int j=v1;j>=0;j--) { for(int k=v2;k>=0;k--) { dp[j][k][1]=max(dp[j][k][1],dp[j][k][0]+hap1[i]); if(j>=cost1[i]) dp[j][k][0]=max(dp[j][k][0],dp[j-cost1[i]][k][0]+hap1[i]), dp[j][k][1]=max(dp[j][k][1],dp[j-cost1[i]][k][1]+hap1[i]); if(k>=cost1[i]) dp[j][k][0]=max(dp[j][k][0],dp[j][k-cost1[i]][0]+hap1[i]), dp[j][k][1]=max(dp[j][k][1],dp[j][k-cost1[i]][1]+hap1[i]); // printf("i=%d,j=%d,k=%d,dp0=%d,dp1=%d\n",i,j,k,dp[j][k][0],dp[j][k][1]); } } } if(dp[v1][v2][1]<maxh)maxn=-1; else { for(int i=0;i<l0;i++) { for(int j=v1;j>=0;j--) { for(int k=v2;k>=0;k--) { if(dp[j][k][0]>=maxh) dp[j][k][1]=max(dp[j][k][1],dp[j][k][0]+hap0[i]); if(j>=cost0[i]&&dp[j-cost0[i]][k][0]>=maxh) dp[j][k][0]=max(dp[j][k][0],dp[j-cost0[i]][k][0]+hap0[i]); if(j>=cost0[i]&&dp[j-cost0[i]][k][1]>=maxh) dp[j][k][1]=max(dp[j][k][1],dp[j-cost0[i]][k][1]+hap0[i]); if(k>=cost0[i]&&dp[j][k-cost0[i]][0]>=maxh) dp[j][k][0]=max(dp[j][k][0],dp[j][k-cost0[i]][0]+hap0[i]); if(k>=cost0[i]&&dp[j][k-cost0[i]][1]>=maxh) dp[j][k][1]=max(dp[j][k][1],dp[j][k-cost0[i]][1]+hap0[i]); // printf("i=%d,j=%d,k=%d,dp0=%d,dp1=%d\n",i,j,k,dp[j][k][0],dp[j][k][1]); } } } maxn=dp[v1][v2][1]; } printf("Case %d: %d\n\n",cas++,maxn); } return 0; }
#include <iostream> #include<cstdio> #include<cstring> using namespace std; int dp[100009],c[100009],w[100009],m[100009]; int n,M,t; void zeropack(int cost,int weight) { for(int i=M;i>=cost;i--) dp[i]=max(dp[i-cost]+weight,dp[i]); } void completepack(int cost,int weight) { for(int i=cost;i<=M;i++) dp[i]=max(dp[i-cost]+weight,dp[i]); } void multipack(int cost,int weight,int num) { if(num*cost>=M) { completepack(cost,weight); return; } int k=1; while(k<num) { zeropack(k*cost,k*weight); num-=k; k*=2; } zeropack(cost*num,weight*num); } int main() { //freopen("cin.txt","r",stdin); while(~scanf("%d%d",&M,&n)) { for(int i=1;i<=n;i++){scanf("%d%d",&m[i],&c[i]);w[i]=c[i];} memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) { multipack(c[i],w[i],m[i]); } printf("%d\n",dp[M]); } return 0; }
做法:很需要那维表示当前物品序号,因为转移方程是dp[i][j]+=dp[i-1][j-pos[k]*weight[i]];
负数的处理,十分纠结于7500是中间值,要是没到这么大的话怎么办啊==看代码#include <iostream> #include<cstdio> #include<cstring> using namespace std; int dp[30][20009]; int c,g,pos[30],weight[30]; int main() { // freopen("cin.txt","r",stdin); // freopen("out.txt","w",stdout); while(~scanf("%d%d",&c,&g)) { for(int i=1;i<=c;i++) { scanf("%d",&pos[i]); //cc[i]+=15; } for(int i=1;i<=g;i++)scanf("%d",&weight[i]); memset(dp,0,sizeof(dp)); dp[0][10000]=1; int maxn=20000; for(int i=1;i<=g;i++) for(int j=0;j<=maxn;j++) for(int k=1;k<=c;k++) if(j>=pos[k]*weight[i]) { dp[i][j]+=dp[i-1][j-pos[k]*weight[i]]; // printf("i=%d,j=%d,k=%d,dp=%d\n",i,j,k,dp[i][j]); } printf("%d\n",dp[g][10000]); } return 0; }
标签:
原文地址:http://blog.csdn.net/zhou_yujia/article/details/51479043