acwing423采药
#include<iostream>
#include<stack>
#include<string.h>
#include<algorithm>
#include<sstream>
using namespace std;
int w[1010];
int cost[1010];
int dp[1010][1010];
int main(){
int t;
int m;
for( int i=1;i<=n;i++){
cin>>cost[i];
cin>>w[i];
}
for( int i=1;i<=m;i++){
for( int j=t;j>=cost[i];j--){
dp[i][j]=max(dp[i][j],dp[i][j-cost[i]]+w[i]);
}
}
cout<<dp[m][t];
}
acwing1024/《信息学奥赛一本通》装箱问题
#include<bits/stdc++.h>
using namespace std;
int a[101];
int dp[20010];
int main(){
int v;
int n;
cin>>v>>n;
for( int i=1;i<=n;i++){
cin>>a[i];
}
for( int i=1;i<=n;i++){
for( int j=v;j>=a[i];j--){
if(dp[j-a[i]]+a[i]<=v)
dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
}
}
cout<<v-dp[v];
}
acwing1022
#include<iostream>
#include<stack>
#include<string.h>
#include<algorithm>
#include<sstream>
using namespace std;
int cos1[1010];
int cos2[1010];
int dp[1010][1010];
int main(){
int n,m,k;
cin>>n>>m>>k;
for( int i=1;i<=k;i++){
cin>>cos1[i]>>cos2[i];
}
for( int i=1;i<=k;i++){
for( int j=n;j>=cos1[i];j--){
for( int t=m;t>cos2[i];t--){
dp[j][t]=max(dp[j][t],dp[j-cos1[i]][t-cos2[i]]+1);
}
}
}
cout<<dp[n][m]<<" ";
if(dp[n][m]==0) {
cout<<m;
return 0;
}
for( int i=m;i>=0;i--){
if(dp[n][i]!=dp[n][i-1]){
cout<<m-i+1;
break;
}
}
}
acwing 278/《算法竞赛进阶指南》数字组合
#include<bits/stdc++.h>
using namespace std;
int a[110];
int dp[10010];
int main(){
int n,m;
cin>>n>>m;
for( int i=1;i<=n;i++){
cin>>a[i];
}
dp[0]=1;
for( int i=1;i<=n;i++){
for( int j=m;j>=a[i];j--){
dp[j]+=dp[j-a[i]];
}
}
cout<<dp[m];
}
acwing 1023/《信息学奥赛一本通》买书问题
#include<bits/stdc++.h>
using namespace std;
int a[110];
int dp[10010];
int main(){
int n,m;
cin>>n>>m;
for( int i=1;i<=n;i++){
cin>>a[i];
}
dp[0]=1;
for( int i=1;i<=n;i++){
for( int j=m;j>=a[i];j--){
dp[j]+=dp[j-a[i]];
}
}
cout<<dp[m];
}
acwing 1021/《信息学奥赛一本通》货币系统
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
int a[20];
ll dp[3010];
int main(){
cin>>n>>m;
for( int i=1;i<=n;i++){
cin>>a[i];
}
dp[0]=1;
for( int i=1;i<=n;i++){
for( int j=a[i];j<=m;j++){
dp[j]+=dp[j-a[i]];
}
}
cout<<dp[m];
}
acwing 532/noip提高组 货币系统
#include<bits/stdc++.h>
using namespace std;
int t,n;
int a[110];
int dp[25100];
int main(){
cin>>t;
while(t--){
cin>>n;
memset(dp,0,sizeof(dp));
for( int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+1+n);
int ans=0;
dp[0]=1;
for( int i=1;i<=n;i++){
if(dp[a[i]]==0) {
ans++;
dp[a[i]]=1;
}
for( int j=a[i];j<=a[n];j++){
dp[j]+=dp[j-a[i]];
}
}
cout<<ans<<endl;
}
}
acwing 1019/《信息学奥赛一本通》庆功会
二进制优化
#include<bits/stdc++.h>
using namespace std;
#define N 510
#define M 6010
int cost1[N],w1[N],s[N];
int m,n;
int cost[M],w[M];
int cnt=1;
int dp[6010];
int main(){
cin>>n>>m;
for( int i=1;i<=n;i++){
cin>>cost1[i]>>w1[i]>>s[i];
int num=1;
while(num<=s[i]){
cost[cnt]=num*cost1[i];
w[cnt++]=num*w1[i];
s[i]-=num;
num*=2;
}
if(s[i]){
cost[cnt]=s[i]*cost1[i];
w[cnt++]=s[i]*w1[i];
}
}
for( int i=1;i<cnt;i++){
for( int j=m;j>=cost[i];j--){
dp[j]=max(dp[j],dp[j-cost[i]]+w[i]);
}
}
cout<<dp[m]<<endl;
}
acwing 7 混合背包问题
#include<bits/stdc++.h>
using namespace std;
#define N 1010
#define M 10010
int n,v;
int w[M],cost[M],type[M],cnt=1;
int dp[N];
int main(){
cin>>n>>v;
for( int i=1;i<=n;i++){
int a,b,c;
cin>>a>>b>>c;
if(c==-1||c==0){
cost[cnt]=a;
w[cnt]=b;
type[cnt++]=c;
}
else {
int num=1;
while(num<=c){
cost[cnt]=a*num;
w[cnt]=b*num;
type[cnt++]=-1;
c-=num;
num*=2;
}
if(c){
cost[cnt]=c*a;
w[cnt]=b*c;
type[cnt++]=-1;
}
}
}
for( int i=1;i<cnt;i++){
if(type[i]==-1){
for( int j=v;j>=cost[i];j--){
dp[j]=max(dp[j],dp[j-cost[i]]+w[i]);
}
}
else{
for( int j=cost[i];j<=v;j++){
dp[j]=max(dp[j],dp[j-cost[i]]+w[i]);
}
}
}
cout<<dp[v]<<endl;
}
acwing 8 二位费用背包问题
#include<bits/stdc++.h>
using namespace std;
#define N 1010
#define M 110
int n,v,m;
int cost1[N],cost2[N],w[N];
int dp[N][N];
int main(){
cin>>n>>v>>m;
for( int i=1;i<=n;i++){
cin>>cost1[i]>>cost2[i]>>w[i];
}
for( int i=1;i<=n;i++){
for( int j=v;j>=cost1[i];j--){
for( int t=m;t>=cost2[i];t--){
dp[j][t]=max(dp[j][t],dp[j-cost1[i]][t-cost2[i]]+w[i]);
}
}
}
cout<<dp[v][m]<<endl;
}
acwing 10 有依赖的背包问题
使用dfs自上而下dfs
首先算出在没有加入根节点时树的最大价值,然后加入根节点。
#include<bits/stdc++.h>
using namespace std;
#define N 110
int w[N],to[N],ne[N],h[N],cost[N];
int cnt,n,v;
int dp[N][N];//第一层枚举节点,第二层枚举容量
void add(int a,int b){
to[cnt]=b;ne[cnt]=h[a],h[a]=cnt++;
}
void dfs(int rt){
if(cost[rt]>v) return;
for( int i=h[rt];i!=-1;i=ne[i]){
int j=to[i];
dfs(j);
}
for( int i=h[rt];i!=-1;i=ne[i]){
int son=to[i];
for( int j=v-cost[rt];j>=0;j--){//枚举容量
for( int d=0;d<=j;d++)
dp[rt][j]=max(dp[rt][j],dp[rt][j-d]+dp[son][d]);
}
}
for( int i=v;i>=cost[rt];i--) dp[rt][i]=dp[rt][i-cost[rt]]+w[rt];
for( int i=0;i<cost[rt];i++) dp[rt][i]=0;
return ;
}
int main(){
memset(h,-1,sizeof(h));
cin>>n>>v;
int root;
for( int i=1;i<=n;i++){
int c;
cin>>cost[i]>>w[i]>>c;
if(c==-1){
root=i;
continue;
}
add( c , i );
}
dfs(root);
// cout<<dp[2][5]<<endl;
cout<<dp[root][v];
return 0;
}
acwing 11
求解背包问题最优解的方法数
开一个和dp数组平行的cnt数组,记录方法数
#include<bits/stdc++.h>
using namespace std;
#define N 1010
#define ll long long
const ll mol =1e9+7;
int w[N],cost[N];
int dp[N];
ll cnt[N];
int n,v;
int main(){
cin>>n>>v;
for( int i=1;i<=n;i++){
cin>>cost[i]>>w[i];
cnt[i]=1;
}
cnt[0]=1;
//注意这里需要把所有的cnt都赋值为1
for( int i=1;i<=n;i++){
for( int j=v;j>=cost[i];j--){
if(dp[j]<dp[j-cost[i]]+w[i]){
dp[j]=dp[j-cost[i]]+w[i];
cnt[j]=cnt[j-cost[i]]%mol;
}//当新状态大于原状态,将原状态用新状态的cnt替换
else if(dp[j]==dp[j-cost[i]]+w[i]){
cnt[j]+=cnt[j-cost[i]]%mol;
}//当新状态等于原状态,将原状态加上新状态的cnt
}
}
cout<<cnt[v]%mol;
}
背包问题求具体方案
对应最短路问题求具体路径。
字典序最小直接贪心即可
dp数组可以看成一棵决策树,一共有三种决策(当可选可不选时,则必选)
若f(i,j)==f(i+1,v-cost[i])则必须选
若f(i,j)!=f(i+1,v-cost[i])则一定不选
求解背包问题的具体方案不能使用状态压缩的方式
#include <bits/stdc++.h>
using namespace std;
#define N 1010
int n,v;
int w[N],cost[N];
int dp[N][N];
int main(){
cin>>n>>v;
for( int i=1;i<=n;i++){
cin>>cost[i]>>w[i];
}
for( int i=n;i>=1;i--){
for( int j=v;j>=0;j--){
//这里注意非状态压缩背包的写法,j要从0开始循环
if(j>=cost[i])
dp[i][j]=max(dp[i+1][j],dp[i+1][j-cost[i]]+w[i]);
else
dp[i][j]=dp[i+1][j];
}
}
int vv=v;
for(int i=1;i<=n;i++){
//注意不要越界
if(vv>=cost[i]&&dp[i][vv]==dp[i+1][vv-cost[i]]+w[i]){
vv-=cost[i];
cout<<i<<" ";
}
else{
continue;
}
}
}