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个物品的特征都互不相同), 最小需要多少次询问? 析:我们假设心中想的那个物 ...
随机推荐
- [C语言] 数据结构-离散存储链表定义
离散存储[链表] 1.定义: n个节点离散分配,彼此通过指针相连 每个节点只有一个前驱节点 只有一个后续节点 首节点没有前驱节点,尾节点没有后续节点 2.专业术语: 首节点:第一个有效节点 尾节点:最 ...
- Notepad++怎么使用正则替换
前言:工作中在oracle中写触发器的sql时,表字段有几十个,修改起来非常不方便,于是采用了Notepad++的替换 案例: 想把 v_update_time,v_create_time,v_rcv ...
- C#设计模式--代理模式(学习Learning hard 设计模式笔记)
class Program { static void Main(string[] args) { //创建一个代理对象 并发出请求 Person proxy = new Friend(); prox ...
- AJAX-XMLHttpRequest和本地文件
网页中可以使用相对URL的能力通常意味着我们能使用本地文件系统来开发和测试HTML,并避免对Web服务器进行不必要的部署. 然而当使用XMLHttpRequest进行Ajax编程时,这通常是不行的. ...
- elixir 模块
模块定义 defmodule 函数定义 def 私有函数 defp --相当于其他语言 private iex(29)> defmodule Math do...(29)> def ...
- GitHub已将持续集成服务器Janky开源
GitHub已将Janky开源,这是他们构建在Jenkins之上的持续集成服务器,并在其中增加了聊天自动化工具Hubot. 除了一般的Jenkins功能之外,Janky还通过Hubot对功能进行了补充 ...
- dev gridview指定单元格cell获取坐标
DevExpress.XtraGrid.Views.Grid.ViewInfo.GridViewInfo Info2 = gvQueryResult.GetViewInfo() as DevExpre ...
- ExpandableListView控件实现二级列表
效果图如下: 二级列表附有点击事件. 1.布局文件: 此处加了一个自定义的导航RelativeLayout,记得注activity的时候添加 android:theme="@style/Th ...
- 2018-10-13 21:30:51 conversion of number systems
2018-10-13 21:30:51 c language 二进制.八进制和十六进制: 1) 整数部分 十进制整数转换为 N 进制整数采用“除 N 取余,逆序排列”法. 十进制数字 36926 转 ...
- sql 中的分隔符
1.通过分隔符可以将其中的内容作为一个整体的字符串进行处理. 假设数据库中有一个表,名为user info,注意这个名字,user 和 info 中间存在一个空格. 如果直接写如下查询,会报错,可能会 ...