链接:

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的价格,而不是输入中的“每股价格”。
最后是打印解的部分。因为状态从前到后定义,因此打印解时需要从后到前打印,用递归比较方便。

代码:

 #include <cstdio>
#include <map>
#include <vector>
using namespace std; typedef long long int LLI;
const LLI INF = 0x3f3f3f3f3f3f3f3f;
const int UPM = + ;
const int UPN = + ;
const int UPS = ;
int m, n, kk, k[UPN];
int buy[UPS][UPN], sell[UPS][UPN], f[UPM][UPS], opt[UPM][UPS];
LLI c, price[UPN][UPM], d[UPM][UPS];
char name[UPN][+];
vector<vector<int> > state;
map<vector<int>,int> id; void dfs(int stock, vector<int>& V, int tot) {
if(stock == n) {
id[V] = state.size();
state.push_back(V);
return;
}
for(int i = ; i <= k[stock] && tot+i <= kk; i++) {
V[stock] = i;
dfs(stock+, V, tot+i);
}
} void init() {
state.clear();
id.clear();
vector<int> V(n);
dfs(, V, );
for(int s = ; s < state.size(); s++) {
int tot = ;
for(int i = ; i < n; i++) tot += state[s][i];
for(int i = ; i < n; i++) {
buy[s][i] = sell[s][i] = -;
if(state[s][i] < k[i] && tot < kk) {
V = state[s];
V[i]++;
buy[s][i] = id[V];
}
if(state[s][i] > ) {
V = state[s];
V[i]--;
sell[s][i] = id[V];
}
}
}
} void update(int day, int s, int s2, LLI v, int o) {
if(d[day+][s2] >= v) return;
d[day+][s2] = v;
f[day+][s2] = s;
opt[day+][s2] = o;
} LLI dynamicProgramming() {
for(int i = ; i <= m; i++)
for(int s = ; s < state.size(); s++) d[i][s] = -INF;
d[][] = c;
for(int day = ; day < m; day++) {
for(int s = ; s < state.size(); s++) {
LLI v = d[day][s];
if(v < -) continue;
update(day, s, s, v, );
for(int i = ; i < n; i++) {
if(buy[s][i] >= && v-price[i][day] >= )
update(day, s, buy[s][i], v-price[i][day], i+);
if(sell[s][i] >= )
update(day, s, sell[s][i], v+price[i][day], -(i+));
}
}
}
return d[m][];
} void output(int day, int s) {
if(day == ) return;
output(day-, f[day][s]);
if(opt[day][s] == ) printf("HOLD\n");
else if(opt[day][s] > ) printf("BUY %s\n", name[opt[day][s]-]);
else printf("SELL %s\n", name[-opt[day][s]-]);
} int main() {
double temp;
int lot, cases = ;
while(~scanf("%lf%d%d%d", &temp, &m, &n, &kk)) {
c = (temp + 1e-) * ;
for(int i = ; i < n; i++) {
scanf("%s%d%d", name[i], &lot, &k[i]);
for(int t = ; t < m; t++) {
scanf("%lf", &temp);
price[i][t] = (LLI)((temp + 1e-) * ) * lot;
}
}
init();
LLI ans = dynamicProgramming();
if(cases++ > ) printf("\n");
printf("%lld.%02lld\n", ans/, ans%);
output(m, );
}
return ;
}

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

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

    题意:题意很难说清楚自己看原文,链接:UVa 1412 Fund Management 析:总体来说如果没有超时的话,这个题不是特别难,但是这个题很容易超时,主要是体现在状态转移时,很容易想到状态方程 ...

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

    UVa 1412 Fund Management 题目: UVA - 1412 Fund Management Time Limit: 3000MS   Memory Limit: Unknown   ...

  3. UVA 1412 Fund Management (预处理+状压dp)

    状压dp,每个状态可以表示为一个n元组,且上限为8,可以用一个九进制来表示状态.但是这样做用数组开不下,用map离散会T. 而实际上很多九进制数很多都是用不上的.因此类似uva 1601 Mornin ...

  4. UVa 1204 Fun Game (状压DP)

    题意:有一些小孩(至少两个)围成一圈,有 n 轮游戏,每一轮从某个小孩开始往左或者往右伟手帕,拿到手帕写上自己的性别(B,G),然后以后相同方向给下一个. 然后在某个小孩结束,给出 n 轮手帕上的序列 ...

  5. UVa 11825 Hackers' Crackdown (状压DP)

    题意:给定 n 个计算机的一个关系图,你可以停止每台计算机的一项服务,并且和该计算机相邻的计算机也会终止,问你最多能终止多少服务. 析:这个题意思就是说把 n 台计算机尽可能多的分成一些组,使得每组的 ...

  6. bzoj 2734 [HNOI2012]集合选数 状压DP+预处理

    这道题很神啊…… 神爆了…… 思路大家应该看别的博客已经知道了,但大部分用的插头DP.我加了预处理,没用插头DP,一行一行来,速度还挺快. #include <cstdio> #inclu ...

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

    有n个物品,每个物品有m个特征.随机选择一个物品让你去猜,你每次可以询问一个特征的答案,问在采取最优策略时,最坏情况下需要猜的次数是多少. 设siz[S]为满足特征性质集合S的特征的物品总数,dp[S ...

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

    Hackers’ Crackdown Miracle Corporations has a number of system services running in a distributed com ...

  9. UVa 1252 Twenty Questions (状压DP+记忆化搜索)

    题意:有n件物品,每件物品有m个特征,可以对特征进行询问,询问的结果是得知某个物体是否含有该特征,要把所有的物品区分出来(n个物品的特征都互不相同), 最小需要多少次询问? 析:我们假设心中想的那个物 ...

随机推荐

  1. MyBatis 常用写法

    MyBatis 常用写法 1.forEach 循环   forEach 元素的属性主要有 item, idnex, collection, open, separator, close. collec ...

  2. SpringCloud Eureka(注册中心集群)

    多个注册中心,其实用不同的配置对应 不同的端口号注册就行了. 注册中心自己也是个服务,看看之前的单个注册中心是怎么样的呢? server: port: 8888 # 服务端口eureka: insta ...

  3. JS基础(二)

    21.标准事件模型的事件类型(包括4个子模块) HTMLEvents:接口为Event,支持的事件类型包括abort.blur.change.error.focus.load.resize.scrol ...

  4. jQuery实现的上下滚动公告栏详细讲解

    之前做项目的时候,一直都想着做一个上下滚动的公告栏,作为展示网站的最新公告信息,因为刚开始自己的思路并不是太清晰,在网上找了很多的源码,但是却发现都不能让自己满意,有的还会出现一些小问题,比如,有时候 ...

  5. springboot项目的重定向和转发

    下面是idea软件创建的项目目录,这里总结了一下转发与重定向的问题,详解如下. 首先解释一下每个文件夹的作用,如果你是用的是idea创建的springboot项目,会在项目创建的一开始resource ...

  6. com.android.builder.packaging.DuplicateFileException: Duplicate files copied in APK META-INF/NOTICE

    在将vivo eclipse sdk 迁移 android studio  时候报错 Error:Execution failed for task ':vivosdk:transformResour ...

  7. 安装部署 OpenPAI Install OpenPAI on Ubuntu

      介绍 不管是机器学习的老手,还是入门的新人,都应该装备上尽可能强大的算力.除此之外,还要压榨出硬件的所有潜力来加快模型训练.OpenPAI作为GPU管理的利器,不管是一块GPU,还是上千块GPU, ...

  8. 如何调试flutter应用

    The Dart Analyzer 这个工具帮助你分析代码,发现可能的错误. 运行命令行 终端进入flutter工程所在目录,执行flutter analyze 使用IntelliJ IDEA Dar ...

  9. maven windows环境nexus3.0私服搭建

    下载 nexus3.x.x 需要JDK1.8版本到sonatype官网下载开源免费的OSS版本,OSS即为Open Source Software.下载地址:https://www.sonatype. ...

  10. 【java8】慎用java8的foreach循环(作废)

    +警告 这篇文章作废掉,是由一个错误的测试方法得到的一个错误结论,后续修正结果正在测试,将贴上. 准确测试已完成:http://www.cnblogs.com/yiwangzhibujian/p/69 ...