• UVa 1412


    链接:

    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
    ");
     85     else if(opt[day][s] > 0) printf("BUY %s
    ", name[opt[day][s]-1]);
     86     else printf("SELL %s
    ", 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("
    ");
    104         printf("%lld.%02lld
    ", ans/100, ans%100);
    105         output(m, 0);
    106     }
    107     return 0;
    108 }
  • 相关阅读:
    Windows_10 系统封装
    leetcode-75 颜色分类
    leetcode-922 按奇偶排序数组 II
    leetcode-905 按奇偶数排序
    UVA-10827 环面上的最大子矩阵和
    leetcode918 环形最大子数组
    leetcode-85 最大矩形
    leetcode-84 柱状图中的最大矩形
    leetcode-221 最大正方形
    leetcode-713 乘积小于k的数组
  • 原文地址:https://www.cnblogs.com/hkxy125/p/9763707.html
Copyright © 2020-2023  润新知