題目
Poj 2063 Investment
Description
John never knew he had a grand-uncle, until he received the notary's letter. He learned that his late grand-uncle had gathered a lot of money, somewhere in South-America, and that John was the only inheritor.
John did not need that much money for the moment. But he realized that it would be a good idea to store this capital in a safe place, and have it grow until he decided to retire. The bank convinced him that a certain kind of bond was interesting for him.
This kind of bond has a fixed value, and gives a fixed amount of yearly interest, payed to the owner at the end of each year. The bond has no fixed term. Bonds are available in different sizes. The larger ones usually give a better interest. Soon John realized that the optimal set of bonds to buy was not trivial to figure out. Moreover, after a few years his capital would have grown, and the schedule had to be re-evaluated.
Assume the following bonds are available:
Value Annual
interest
4000
3000 400
250
With a capital of e10 000 one could buy two bonds of $4 000, giving a yearly interest of $800. Buying two bonds of $3 000, and one of $4 000 is a better idea, as it gives a yearly interest of $900. After two years the capital has grown to $11 800, and it makes sense to sell a $3 000 one and buy a $4 000 one, so the annual interest grows to $1 050. This is where this story grows unlikely: the bank does not charge for buying and selling bonds. Next year the total sum is $12 850, which allows for three times $4 000, giving a yearly interest of $1 200.
Here is your problem: given an amount to begin with, a number of years, and a set of bonds with their values and interests, find out how big the amount may grow in the given period, using the best schedule for buying and selling bonds.
Input
The first line contains a single positive integer N which is the number of test cases. The test cases follow.
The first line of a test case contains two positive integers: the amount to start with (at most $1 000 000), and the number of years the capital may grow (at most 40).
The following line contains a single number: the number d (1 <= d <= 10) of available bonds.
The next d lines each contain the description of a bond. The description of a bond consists of two positive integers: the value of the bond, and the yearly interest for that bond. The value of a bond is always a multiple of $1 000. The interest of a bond is never more than 10% of its value.
Output
For each test case, output – on a separate line – the capital at the end of the period, after an optimal schedule of buying and selling.
Sample Input
1
10000 4
2
4000 400
3000 250
Sample Output
14050
具體的內容就是一共有多組債券,分別給出了每組債券的價格與每年的利息,然后根據投資的年數與投資的初始錢數,計算最終的總價值。
輸入:
N(測試數據數量)
amount(初始錢數) years(年數)
d(債券數量)
value(債券價格) interest(每年的利息)
...(一共 d 組)
思路
核心其實還是背包問題,關鍵有幾個點:
- 初始錢數最大為 1000000,年數最大為 40,利息最大為 10%,有此我們可以計算出最終的結果最大約為 45260000,按照背包的思路,如果直接開這么大的數據內存就直接爆掉了,而題目給了每組債券都是 1000 的整數倍,所以 1000 以下的部分其實跟利息的計算是毫無關系的(僅僅是每年喲),而 1000 以上的部分可以直接通過除掉 1000 來減小數組的大小,這樣數組其實開到 45260 就可以了。
- 先暴力計算出所有可能金錢得到的利息數(即 result[]),這樣在以后每年計算的時候都可以直接取值就可以了
- 剩下的問題就是計算 result[] 了,標準的背包問題,這里我就不細說了,如果不了解的話直接看《背包九講》吧。
代碼
// http://poj.org/problem?id=2063
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstring>
#include<math.h>
using namespace std;
#define max(x,y) (x > y ? x : y)
//債券
struct Bond {
// 債券的價格
int value;
// 債券的利息
int interest;
};
// 債券的總列表
Bond bondList[15];
// index 代表金額(除以 1000 后的值),result[index] 為這個金額最大的利息數
int result[50000];
/**
* 根據債券的信息,更新 result 數據
**/
void updateResult(int maxAmount, int boudNum) {
for (int i = 0; i < boudNum; i++) {
int value = bondList[i].value;
int interest = bondList[i].interest;
int lastMax = 0;
for(int t = 0; t <= maxAmount - value; t++) {
if (result[t] != 0) {
lastMax = result[t];
}
result[t + value] = max(result[t + value], result[t] + interest);
if (result[t] == 0) {
result[t] = lastMax;
}
}
}
}
/**
* 根據 updateResult 計算出來的結果,計算最終結果
**/
int calculate(int amount, int years) {
int total = amount;
for(int i = 0; i < years; i++) {
total += result[total / 1000];
}
return total;
}
int main(int argc, const char * argv[]) {
// 處理輸入數據,不多解釋
int n, amount, years, boudNum;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d %d %d", &amount, &years, &boudNum);
for (int t = 0; t < boudNum; t++) {
scanf("%d %d", &bondList[t].value, &bondList[t].interest);
// 因為債券的價格都是 1000 的整數倍,所以這里可以除掉 1000
bondList[t].value /= 1000;
}
// 初始化數據,避免每個 testcase 互相影響
memset(result, 0, sizeof(result));
// 復利,每年最高 10%,可以計算出最大的可能結果,剪枝,避免過多的計算
int maxAmount = ((int)(pow(1.1, years) * amount / 1000) + 1);
updateResult(maxAmount, boudNum);
printf("%d\n", calculate(amount, years));
}
}