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 }

 

posted @ 2018-10-09 22:58  Ctfes  阅读(271)  评论(0编辑  收藏  举报