背包问题

Luogu1855 榨取kkksc03

每个愿望需要金钱(m_i) , 时间(t_i) . 求最多能满足多少个愿望

很好的例题 : 01背包 : 从大往小选 , 详见代码
即对于每个物品都直接更新 , 但顺序是从大到小以避免重复.

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
    register LL x=0,f=1;register char c=getchar();
    while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
    while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
    return f*x;
}

int m[105],t[105],dp[205][205],n,M,T;

int main(){
	n=read(),M=read(),T=read();
	for(int i=1;i<=n;i++){
		m[i]=read(),t[i]=read();
		for(int j=M;j>=m[i];j--){
			for(int k=T;k>=t[i];k--)
				dp[j][k]=max(dp[j][k],dp[j-m[i]][k-t[i]]+1);
		}
	}
	printf("%d
",dp[M][T]);
}

Luogu1417 烹调方案

一共有(n)件食材,每件食材有三个属性,(a_i)(b_i)(c_i),如果在(t)时刻完成第(i)样食材则得到(a_i-t*b_i)的美味指数,用第(i)件食材做饭要花去(c_i)的时间 , 求在时间(T)内能获得最大美味指数.

现在考虑相邻的两个物品(x,y).假设现在已经耗费(t)的时间,那么分别列出先做(x,y)的代价:
(a[x]-(t+c[x])*b[x]+a[y]-(t+c[x]+c[y])*b[y]dots)
(a[y]-(t+c[y])*b[y]+a[x]-(t+c[y]+c[x])*b[x]dots)
对这两个式子化简,得到①>②的条件是(c[y]*b[x]>c[x]*b[y])

然后按照顺序(01)背包的选法来选.

后加入的时间在后面 , 所以需要排序
排好序还要再选背包?考虑当前空间下怎么选最优

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
    register LL x=0,f=1;register char c=getchar();
    while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
    while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
    return f*x;
}

const int N=55;
const int M=100005;

struct Node{
    int a,b,c;
}a[N];
inline bool cmp(const Node& x,const Node& y){
    return 1ll*x.b*y.c>1ll*y.b*x.c;
}

LL f[M],ans=-INF;
int T,n;

int main(){
    T=read(),n=read();
    for(int i=1;i<=n;i++) a[i].a=read();
    for(int i=1;i<=n;i++) a[i].b=read();
    for(int i=1;i<=n;i++) a[i].c=read();
    sort(a+1,a+n+1,cmp);
    memset(f,0xcf,sizeof f);
    f[0]=0;
    for(int i=1;i<=n;i++){
        for(int j=T-a[i].c;j>=0;j--)
            if(f[j]!=-1)
                f[j+a[i].c]=max(f[j+a[i].c],f[j]+(LL)a[i].a-(LL)(j+a[i].c)*a[i].b);
				//后加入的时间在后面,所以需要排序
				//排好序还要再选背包?考虑当前空间下怎么选最优
    }
    for(int i=0;i<=T;i++)
        ans=max(ans,f[i]);
    printf("%lld
",ans);
}

Luogu1474 货币系统

给定(n)种货币 , 求组成面值(m)的方案数 .
直接对于每一个新加进来的数 , 它可以对所有数产生影响,即(f[j]+=f[j-a[i]]) .
这里是完全背包 , 每种面值可以选无限次 , 所以循环顺序从小到大 .

#include<iostream>
using namespace std;
long long f[100005];
int a[31],n,m;
int main(){
	cin>>n>>m;
	f[0]=1;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		for(int j=a[i];j<=m;j++)
			f[j]+=f[j-a[i]];
	}
	cout<<f[m]<<endl;
}
原文地址:https://www.cnblogs.com/lizehon/p/10940269.html