POJ 2063 Investment(完全背包)
http://poj.org/problem?id=2063
题意:
初始时有m (m<=10000) 美元,现在有n只股票,每只股票如果购买一份的话当前的利润也给出了(可以无限购买). 假设你第一年用m美元买了股票,这年结束的时候你就会把所有股票原价卖出并且得到你所有股票的利润. 然后你又开始第2年股票的投资了...(股票的价格都是1000的整数倍,且每只股票的年收益率<=10%)
现在你需要连续买t年(t<=40) 的股票, 问你t年后你的总钱数是多少.
分析:
由于有n只股票且每只股票可以无限买, 所以本题可以把每一年的投资看成是一个完全背包问题. 然后用前一年的利润+本钱继续进行下一年的投资(又是一个完全背包过程).
由于每年投资的本金到年尾还是能回来的,所以我们只需要求出每年的最大利润即可. 所以本题可以变成下面的问题:
你手上有m美元, 然后有n种物品你可以无限买, 每种物品具有不同的价格cost[i] 和价值val[i]. 现在你需要在花费<=m美元的前提下使得物品总价值sum_val最大?
上面就是一个标准的完全背包问题. 但是本题的m<=10000, 且股票收益最大可达10% 且最多投资40年, 所以10000*(1.1)^40 == 4500W左右. 我们不可能每轮都用dp[450000000]的数组去做的.
题目说了每个股票价格都是1000的倍数, 而这里我们只要求出一年用m美元能得到的最大利润即可.所以我们把上面问题变成下面的问题:
初始你手里有m/1000 个资源(每个资源代表1000美元) , 你有n种物品可以买, 每种物品需要cost[i]/1000个资源才能买 且 你能获得val[i]的价值, 问你最多能获得多少价值?
这样我们的数组只要开dp[450000]即可. 现在我们来解决一次完全背包问题.
令dp[i][j]==x 表用前i个物品在总花费<=j 时, 最多能获得价值x.
初始化: dp全0.
状态转移: dp[i][j] = max( dp[i-1][j] , dp[i][j-cost[i]]+val[i])
前者代表第i个物品一个都不买, 后者代表至少买1个第i个物品.
最终我们所求为 dp[n][m]. (这个就是本年最大利润)
在每轮投资的末尾, 把当年最大利润加到本金m上就得到了下一年开始时的本金数目了. 一共t年后即可求得最后的最大金额.
AC代码:
#include<algorithm> #include<cstring> #include<cstdio> using namespace std; const int maxn=46000+5; int n;//共n种基金 int m;//初始m美元 int t;//需要买t年 int cost[10+5];//每种基金价格 x千美元 int val[10+5]; //每种基金年收益 x美元 int dp[maxn]; int main() { int T; scanf("%d",&T); while(T--) { //读输入数据 scanf("%d%d%d",&m,&t,&n); for(int i=1;i<=n;i++) { scanf("%d%d",&cost[i],&val[i]); cost[i]/=1000;//第i个股票需要cost[i]千美元来买 } //每年的处理过程 for(int loop=1;loop<=t;loop++) { int max_money=m/1000;//max_money是本年能用多少(千美元) memset(dp,0,sizeof(dp)); //递推过程 for(int i=1;i<=n;i++) { for(int j=cost[i];j<=max_money;j++) dp[j] = max(dp[j], dp[j-cost[i]]+val[i]); } m+=dp[max_money];//当年利润叠加到总金钱上 } //输出结果 printf("%d\n",m); } return 0; }