ACM学习总结之背包问题
这周学习了背包问题。
背包问题属于一种线性规划的模型。它可分为好几类。包括01背包,完全背包等问题。
01背包:有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
设f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值,则可得状态转移方程f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]};由于对于每一个下标为i的状态,它的值仅有它的上一个下标为i-1的状态决定,则可进行空间优化,得到 f[v]=max{f[v],f[v-c[i]]+w[i]};需要注意的是,对一维数组进行遍历是容量逆序遍历,只有逆序遍历,才能保证第i件物品时方程中
f[v-c[i]]是对应i-1物品的值。
代码
#include<iostream>
using namespace std;
#define MAX_N 3500
#define MAX_V 20000
struct good
{
int c;
int w;
}goods[MAX_N];
int main()
{
int i,j;
int n,v;
int f[MAX_V];
while(cin>>n>>v)
{
for(i=0;i<=v;i++)f[i]=0;
for(i=0;i<=n;i++)cin>>goods[i].c>>goods[i].w;
for(i=0;i<=n;i++)
{
for(j=v;j>=goods[i].c;j--)
{
if(f[j]<f[j-goods[i].c]+goods[i].w)
f[j]=f[j-goods[i].c]+goods[i].w;
}
}
cout<<f[v]<<endl;
}
return 0;
}
完全背包:
有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
与01背包不同的是每件物品的数量不限定只要小于背包空间可随便取,得到的状态转移方程为f[i][j]=max{f[i-1][j-kw[i]]+kv[i]|0=<k<=V/w[i]}。
代码:
for(int i=1;i<=n;i++)
{
for(int j=0;j<=V;j++)
{
f[i][j]=f[i-1][j];
for(int k=0;k<=V/v[i];k++)
{
if(j-k*v[i]>=0)
{
f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*c[i]);
}
}
}
}
int ans=0;
for(int i=0;i<=V;i++)
ans=max(ans,f[n][i]);
printf("%d\n",ans);
优化后得到f[i][v]=max{f[i-1][v],f[i][v-c[i]]+w[i]};代码为
for(int i=1;i<=n;i++)
{
for(int j=0;j<=V;j++)
{
if(j-v[i]>=0)
f[j]=max(f[j],f[j-v[i]]+c[i]);
}
}
printf("%d\n",f[n]);
题目:
Recently, iSea went to an ancient country. For such a long time, it was the most wealthy and powerful kingdom in the world. As a result, the people in this country are still very proud even if their nation hasn’t been so wealthy any more.
The merchants were the most typical, each of them only sold exactly one item, the price was Pi, but they would refuse to make a trade with you if your money were less than Qi, and iSea evaluated every item a value Vi.
If he had M units of money, what’s the maximum value iSea could get?
题意:有n个商品,你有一定的钱,每件商品都有其价格、价值及其购买的前提资金。你的金钱必须大于商品的前提资金才能买那个商品。求获得的最大价值。此题为01背包的变形,与01背包的区别为商品多了个前提资金,为了尽可能多的获得价值,先对商品的前提资金排序,便转换成了01背包问题。
代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string>
using namespace std;
struct node
{
const bool operator<(const node&rhs)const {
return m < rhs.m;
}
int a, b, c;
int m;
};
node s[5050];
int dp[5050];
int main() {
int N, M;
while (scanf("%d %d", &N, &M) != EOF) {
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= N; i++) {
scanf("%d %d %d", &s[i].a, &s[i].b, &s[i].c);
s[i].m = s[i].b - s[i].a;
}
sort(s, s + N);
for (int i = 1; i <= N; i++) {
for (int j = M; j >= s[i].a; j--) {
if (j >= s[i].b) {
dp[j] = max(dp[j], dp[j - s[i].a] + s[i].c);
}
}
}
printf("%d\n", dp[M]);
}
return 0;
}