UVa 1412 - Fund Management(状压DP + 预处理)

链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4158

题意:

你有c(0.01≤c≤1e8)美元现金,但没有股票。给你m(1≤m≤100)天时间和n(1≤n≤8)支股票供你买卖,
要求最后一天结束后不持有任何股票,且剩余的钱最多。买股票不能赊账,只能用现金买。
已知每只股票每天的价格(0.01~999.99。单位是美元/股)与参数si和ki,
表示一手股票是si(1≤si≤1e6)股,且每天持有的手数不能超过ki(1≤ki≤k),其中k为每天持有的总手数上限。
每天要么不操作,要么选一只股票,买或卖它的一手股票。c和股价均最多包含两位小数(即美分)。
最优解保证不超过1e9。要求输出每一天的决策(HOLD表示不变,SELL表示卖,BUY表示买)。

分析:

以用d(i,p)表示经过i天之后,资产组合为p时的现金的最大值。其中p是一个n元组,pi≤ki表示第i只股票有pi手。
根据题目规定,p1+…+pn≤k。因为0≤pi≤8,理论上最多只有9^8<5e7种可能,所以可以用一个九进制整数来表示p。
一共有3种决策:HOLD、BUY和SELL,分别进行转移即可。
注意在考虑购买股票时不要忘记判断当前拥有的现金是否足够。
但是这样的做法效率不够高,因为九进制整数无法直接进行“买卖股票”的操作,需要解码成n元组才行。
因为几乎每次状态转移都会涉及编码、解码操作,状态转移的时间大幅度提升,最终导致超时。
解决方法是事先计算出所有可能的状态并且编号,然后构造一个状态转移表,
用buy[s][i]和sell[s][i]分别表示状态s进行“买股票i”和“卖股票i”之后转移到的状态编号。
动态规划主程序采用刷表法,为了方便起见,另外编写了“更新状态”的函数update。
为了打印解,在更新解d时还要更新最优策略opt和“上一个状态”f。
注意代码中的price[i][day]表示第day天时一手股票i的价格,而不是输入中的“每股价格”。
最后是打印解的部分。因为状态从前到后定义,因此打印解时需要从后到前打印,用递归比较方便。

代码:

  1 #include <cstdio>
  2 #include <map>
  3 #include <vector>
  4 using namespace std;
  5
  6 typedef long long int LLI;
  7 const LLI INF = 0x3f3f3f3f3f3f3f3f;
  8 const int UPM = 100 + 5;
  9 const int UPN = 8 + 5;
 10 const int UPS = 15000;
 11 int m, n, kk, k[UPN];
 12 int buy[UPS][UPN], sell[UPS][UPN], f[UPM][UPS], opt[UPM][UPS];
 13 LLI c, price[UPN][UPM], d[UPM][UPS];
 14 char name[UPN][5+5];
 15 vector<vector<int> > state;
 16 map<vector<int>,int> id;
 17
 18 void dfs(int stock, vector<int>& V, int tot) {
 19     if(stock == n) {
 20         id[V] = state.size();
 21         state.push_back(V);
 22         return;
 23     }
 24     for(int i = 0; i <= k[stock] && tot+i <= kk; i++) {
 25         V[stock] = i;
 26         dfs(stock+1, V, tot+i);
 27     }
 28 }
 29
 30 void init() {
 31     state.clear();
 32     id.clear();
 33     vector<int> V(n);
 34     dfs(0, V, 0);
 35     for(int s = 0; s < state.size(); s++) {
 36         int tot = 0;
 37         for(int i = 0; i < n; i++) tot += state[s][i];
 38         for(int i = 0; i < n; i++) {
 39             buy[s][i] = sell[s][i] = -1;
 40             if(state[s][i] < k[i] && tot < kk) {
 41                 V = state[s];
 42                 V[i]++;
 43                 buy[s][i] = id[V];
 44             }
 45             if(state[s][i] > 0) {
 46                 V = state[s];
 47                 V[i]--;
 48                 sell[s][i] = id[V];
 49             }
 50         }
 51     }
 52 }
 53
 54 void update(int day, int s, int s2, LLI v, int o) {
 55     if(d[day+1][s2] >= v) return;
 56     d[day+1][s2] = v;
 57     f[day+1][s2] = s;
 58     opt[day+1][s2] = o;
 59 }
 60
 61 LLI dynamicProgramming() {
 62     for(int i = 0; i <= m; i++)
 63         for(int s = 0; s < state.size(); s++) d[i][s] = -INF;
 64     d[0][0] = c;
 65     for(int day = 0; day < m; day++) {
 66         for(int s = 0; s < state.size(); s++) {
 67             LLI v = d[day][s];
 68             if(v < -1) continue;
 69             update(day, s, s, v, 0);
 70             for(int i = 0; i < n; i++) {
 71                 if(buy[s][i] >= 0 && v-price[i][day] >= 0)
 72                     update(day, s, buy[s][i], v-price[i][day], i+1);
 73                 if(sell[s][i] >= 0)
 74                     update(day, s, sell[s][i], v+price[i][day], -(i+1));
 75             }
 76         }
 77     }
 78     return d[m][0];
 79 }
 80
 81 void output(int day, int s) {
 82     if(day == 0) return;
 83     output(day-1, f[day][s]);
 84     if(opt[day][s] == 0) printf("HOLD\n");
 85     else if(opt[day][s] > 0) printf("BUY %s\n", name[opt[day][s]-1]);
 86     else printf("SELL %s\n", name[-opt[day][s]-1]);
 87 }
 88
 89 int main() {
 90     double temp;
 91     int lot, cases = 0;
 92     while(~scanf("%lf%d%d%d", &temp, &m, &n, &kk)) {
 93         c = (temp + 1e-3) * 100;
 94         for(int i = 0; i < n; i++) {
 95             scanf("%s%d%d", name[i], &lot, &k[i]);
 96             for(int t = 0; t < m; t++) {
 97                 scanf("%lf", &temp);
 98                 price[i][t] = (LLI)((temp + 1e-3) * 100) * lot;
 99             }
100         }
101         init();
102         LLI ans = dynamicProgramming();
103         if(cases++ > 0) printf("\n");
104         printf("%lld.%02lld\n", ans/100, ans%100);
105         output(m, 0);
106     }
107     return 0;
108 }

原文地址:https://www.cnblogs.com/hkxy125/p/9763707.html

时间: 2024-10-29 00:15:00

UVa 1412 - Fund Management(状压DP + 预处理)的相关文章

UVA 11825 Hackers&#39; Crackdown 状压DP

感觉白书上的做法很神! 首先状压表示电脑之间的联通关系,然后预处理出所有关闭电脑的组合达到的状态,然后枚举每个状态并且枚举每个状态的所有子集,之后无脑递推就木有了. 关于枚举一个状态所有子集的小技巧:假设当前状态是S0 有 for s = s0; s != 0; s =  (s - 1) & s0 #include <cstdio> #include <cstring> #include <iostream> #include <map> #incl

【暑假】[深入动态规划]UVa 1412 Fund Management

UVa 1412 Fund Management 题目: UVA - 1412 Fund Management Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description Frank is a portfolio manager of a closed-end fund for Advanced Commercial Markets (ACM ). Fund

UVA 11691 - Allergy Test(状压dp+贪心)

题目链接:11691 - Allergy Test 题意:这题题意看了老半天都没弄懂,好在后面找到个PPT,上面有中文题意- -,不过上面的做法是纯贪心,挺巧妙的但是感觉有点不靠谱, 下载地址:http://par.cse.nsysu.edu.tw/~advprog/advprog2011/11691.ppt 給N種過敏原的存活期,每天可把一種過敏原注入人體內.若有兩個以上過敏原存活於人體中,則無法進行實驗(也就是每種過敏原都必須有一天是單獨存活於人體中).實驗結束於最後的過敏原死亡的那天,求最

UVA 1252 Twenty Questions 状压DP

简单状压DP: 当前状态s如果这个物品有状态a个属性,枚举下一个要猜测的特征k dp[s][a]=min(dp[s][a],max(dp[s+k][a],dp[s+k][a+k])+1); 4643 - Twenty Questions Asia - Tokyo - 2009/2010 Consider a closed world and a set of features that are defined for all the objects in the world. Each feat

UVA 1412 - Fund Management(用vector容器模拟状态的状压dp)

Frank is a portfolio manager of a closed-end fund for Advanced Commercial Markets (ACM ). Fund collects money (cash) from individual investors for a certain period of time and invests cash into various securities in accordance with fund's investment

UVA 11825 Hackers’ Crackdown 状压DP枚举子集势

Hackers’ Crackdown Miracle Corporations has a number of system services running in a distributed computer system which is a prime target for hackers. The system is basically a set of N computer nodes with each of them running a set of Nservices. Note

UVA - 1252 Twenty Questions (状压dp+vis数组加速)

有n个物品,每个物品有m个特征.随机选择一个物品让你去猜,你每次可以询问一个特征的答案,问在采取最优策略时,最坏情况下需要猜的次数是多少. 设siz[S]为满足特征性质集合S的特征的物品总数,dp[S]为当前得到的物品特征信息为S的情况下最坏情况下需要猜多少次,则$dp[S]=max\{dp(S|(1<<(2*i))),dp(S|(2<<(2*i))\}$(为了表示某个特征不确定的状态,需要将集合大小加倍).dfs预处理siz的复杂度为$O(n*2^m)$,dp的复杂度为$O(m*

(状压dp)uva 10817 Headmaster&#39;s Headache

题目地址 1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int MAX=1e5+5; 5 const int INF=1e9; 6 int s,m,n; 7 int cost[125]; 8 //char sta[MAX]; 9 string sta; 10 int able[125]; 11 int dp[125][1<<8][1<<8]; 12 in

UVA 10817 Headmaster&#39;s Headache 状压DP

记录两个状态S1,S2分别记录哪些课程被1个人教过或2个人教过,然后记忆化搜索 UVA - 10817 Headmaster's Headache Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description Problem D: Headmaster's Headache Time limit: 2 seconds The headmaster of Spr