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的价格,而不是输入中的“每股价格”。
最后是打印解的部分。因为状态从前到后定义,因此打印解时需要从后到前打印,用递归比较方便。
代码:
#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 + 预处理)的更多相关文章
- UVa 1412 Fund Management (预处理+状压DP)
题意:题意很难说清楚自己看原文,链接:UVa 1412 Fund Management 析:总体来说如果没有超时的话,这个题不是特别难,但是这个题很容易超时,主要是体现在状态转移时,很容易想到状态方程 ...
- 【暑假】[深入动态规划]UVa 1412 Fund Management
UVa 1412 Fund Management 题目: UVA - 1412 Fund Management Time Limit: 3000MS Memory Limit: Unknown ...
- UVA 1412 Fund Management (预处理+状压dp)
状压dp,每个状态可以表示为一个n元组,且上限为8,可以用一个九进制来表示状态.但是这样做用数组开不下,用map离散会T. 而实际上很多九进制数很多都是用不上的.因此类似uva 1601 Mornin ...
- UVa 1204 Fun Game (状压DP)
题意:有一些小孩(至少两个)围成一圈,有 n 轮游戏,每一轮从某个小孩开始往左或者往右伟手帕,拿到手帕写上自己的性别(B,G),然后以后相同方向给下一个. 然后在某个小孩结束,给出 n 轮手帕上的序列 ...
- UVa 11825 Hackers' Crackdown (状压DP)
题意:给定 n 个计算机的一个关系图,你可以停止每台计算机的一项服务,并且和该计算机相邻的计算机也会终止,问你最多能终止多少服务. 析:这个题意思就是说把 n 台计算机尽可能多的分成一些组,使得每组的 ...
- bzoj 2734 [HNOI2012]集合选数 状压DP+预处理
这道题很神啊…… 神爆了…… 思路大家应该看别的博客已经知道了,但大部分用的插头DP.我加了预处理,没用插头DP,一行一行来,速度还挺快. #include <cstdio> #inclu ...
- UVA - 1252 Twenty Questions (状压dp+vis数组加速)
有n个物品,每个物品有m个特征.随机选择一个物品让你去猜,你每次可以询问一个特征的答案,问在采取最优策略时,最坏情况下需要猜的次数是多少. 设siz[S]为满足特征性质集合S的特征的物品总数,dp[S ...
- UVA 11825 Hackers’ Crackdown 状压DP枚举子集势
Hackers’ Crackdown Miracle Corporations has a number of system services running in a distributed com ...
- UVa 1252 Twenty Questions (状压DP+记忆化搜索)
题意:有n件物品,每件物品有m个特征,可以对特征进行询问,询问的结果是得知某个物体是否含有该特征,要把所有的物品区分出来(n个物品的特征都互不相同), 最小需要多少次询问? 析:我们假设心中想的那个物 ...
随机推荐
- [转] 如何应用设计模式设计你的足球引擎(三和四)----Design Football Game(Part III and IV)
原文地址:http://www.codeproject.com/KB/cpp/applyingpatterns2.aspx 作者:An 'OOP' Madhusudanan 译者:赖勇浩(http:/ ...
- Java虚拟机_运行时数据区
Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域. 这些区域都有各自的用途.各自的创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程启动 ...
- 14、通过jpa往数据库插数据
这是接着上一篇写的,在上一篇的基础上添加 Controller @RestController public class HelloController { @Resource private Hel ...
- jackson @ResponseBody 处理日期类型的字段
前言:以前只知道一种方式(@JsonFormat)来处理日期格式问题,今天才发现还有两种方式,并且可以全局设置格式,这里记录一下. 首先,pom.xml 中需要先引入如下 jackson 的依赖: & ...
- 【学习笔记】--- 老男孩学Python,day15 python内置函数大全,递归,二分法
1. lamda匿匿名函数2. sorted()3. filter()4. map()5. 递归函数 一. lamda 匿名函数 为了了解决一些简单的需求⽽设计的⼀句话函数 语法: 函数名 = lam ...
- Python爬虫学习记录【内附代码、详细步骤】
引言: 昨天在网易云课堂自学了<Python网络爬虫实战>,视频链接 老师讲的很清晰,跟着实践一遍就能掌握爬虫基础了,强烈推荐! 另外,在网上看到一位学友整理的课程记录,非常详细,可以优先 ...
- iframe的探讨
用法 1.iframe是用来在网页中插入第三方页面,早期的页面使用iframe主要是用于导航栏这种很多页面都相同的部分,这样在切换页面的时候避免重复下载. 优点 1.便于修改,模拟分离,像一些信息管理 ...
- 2016最新Java学习计划
一.Java学习路线图 二.Java学习路线图--视频篇 六大阶段 学完后目标 知识点 配套免费资源(视频+笔 记+源码+模板) 密码 第一阶段 Java基础 入门 学习周期: 35天 ...
- mysql 运行 sql 脚本
方式一: 打开脚本,复制里面的全部内容,登陆数据库后运行. 方式二: window cmd 运行如下命令: mysql -u root -proot --port 3306 <D:\simple ...
- angularjs初识ng-app、ng-model、ng-repeat指令
ng-app属性是angular.js的标志语句,它标记了angular.js的作用域.ng-app可以添加在很多地方,像上面那样添加到html标签上,说明angular脚本对整个页面都起作用.也可以 ...