The cicerone’s abacus
总提交:1015 测试通过:337
描述
输入
The input file contains multiple test cases. For each case the first line includes a positive integer n representing the number of sightseers who intend to buy souvenirs. The second line includes n integers each of which is the maximum budget (positive integer and less than 2000) each sightseer plans to spend. There is a positive integer m (m<101) in the following line indicating the categories of the goods. Then comes m lines. Each line has two integers. The first is the price p of the goods (p<1000) and the second is the value of the relevant kickback (no more than 0.2p).
输出
For each test case output one line contains the maximum value of the kickback the cicerone can obtain.
样例输入
3
200 300 300
5
12 2
20 4
30 5
50 5
100 18
样例输出
160
题目来源
NUAA
Currently for the requirement of the sightseers, many cicerones often take them to shopping for some souvenirs in addition to the introduction of the local culture and historic sites. Some souvenir shops give the cicerones who bring sightseers some kickbacks in order to make them bring more. The amount of the kickback is determined by the value of the goods. The shops usually list the values of the goods and the relevant kickbacks for the cicerones to make them clear of the reward they can earn from each kind of goods.
Assume the cicerone has known the maximum amount of money every sightseer intends to spend and the trust of the sightseers on him. The sightseers will buy all souvenirs in any quantity recommended by the cicerone only if their maximum budgets are kept. Before going to the shop, the cicerone starts calculating which goods he should recommend to which sightseer so as to make himself obtain the maximum kickbacks. Unfortunately, this is such a hard problem for him that he never works it out.
Luckily, the cicerone meets you who is good at programming, so he hopes you can program to finish this job. Assume the shop has enough quantity of every goods to meet the shopping requirement of all sightseers.
#include<iostream>
#include<string>
using namespace std;
int dn[101][2001];
int price[101];
int person[2001];
int back[101];
int main()
{
int T,m,i,j,k;
while(cin>>T)
{
for(i=0;i<T;i++)
cin>>person[i];
cin>>m;
for(j=0;j<m;j++)
cin>>price[j]>>back[j];
int sum=0,max;
for(int s=0;s<T;s++)
{
memset(dn,0,sizeof(dn));
for(i=1;i<=m;i++)
for(j=1;j<=person[s];j++)
{
max=0;
//max=dn[i-1][j]也可以
for(k=0;k<=j/price[i-1];k++)
{
if(dn[i-1][j-k*price[i-1]]+k*back[i-1]>max)
max=dn[i-1][j-k*price[i-1]]+k*back[i-1];
}
dn[i][j]=max;
}
sum+=dn[m][person[s]];
}
cout<<sum<<endl;
}
}
完全背包问题
题目
有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
基本思路
这个问题非常类似于01背包问题,所不同的是每种物品有无限件。也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件……等很多种。如果仍然按照解01背包时的思路,令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值。仍然可以按照每种物品不同的策略写出状态转移方程,像这样:
f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v}
这跟01背包问题一样有O(VN)个状态需要求解,但求解每个状态的时间已经不是常数了,求解状态f[i][v]的时间是O(v/c[i]),总的复杂度可以认为是O(V*Σ(V/c[i])),是比较大的。
将01背包问题的基本思路加以改进,得到了这样一个清晰的方法。这说明01背包问题的方程的确是很重要,可以推及其它类型的背包问题。但我们还是试图改进这个复杂度。