链接:

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. 转载:sql用逗号连接多张表对应哪个join?

    http://blog.csdn.net/huanghanqian/article/details/52847835 四种join的区别已老生常谈: INNER JOIN(也可简写为JOIN): 如果 ...

  2. SpringBoot配置——@PropertySource、@ImportResource、@Bean

    @PropertySource:加载指定的配置文件 package com.hoje.springboot.bean; import org.springframework.beans.factory ...

  3. manven springmvc 项目中 slf4j 的配置使用(结合log4j 或者 logback)

    前言:每个maven springmvc 都应该有日志功能,SLF4J(Simple logging facade for Java)就是一种日志规范,它提供了一个共通接口,可以适配多种不同的LOG实 ...

  4. xamarin.Android SQLite存储

    在可移植类库 新建: using SQLite.Net.Interop; using System; using System.Collections.Generic; using System.Li ...

  5. drupal7设置不含www的url跳转到含www的url

    打开drupal的.htaccess文件 找到 If your site can be accessed both with and without the 'www.' prefix 将下面对应的三 ...

  6. TCP报文发送工具

    该工具用于向Socket服务端发送XML报文,软件功能界面如下图所示: 配置好IP和端口后,单击"载入报文文件"按钮,在文件选择对话框中选择报文文件,如图: 报文文件打开后,可在右 ...

  7. Pwn with File结构体之利用 vtable 进行 ROP

    前言 本文以 0x00 CTF 2017 的 babyheap 为例介绍下通过修改 vtable 进行 rop 的操作 (:-_- 漏洞分析 首先查看一下程序开启的安全措施 18:07 haclh@u ...

  8. angularjs -- 监听angularJs列表数据是否渲染完毕

    前端在做数据渲染的时候经常会遇到在数据渲染完毕后执行某些操作,这几天就一直遇到在列表和表格渲染完毕后,执行点击和选择操作.对于angularjs处理这类问题,最好的方式就是指令 directive. ...

  9. 你写的什么垃圾代码让Vsync命令不能及时处理呢?(1)

    想想自己写的什么垃圾代码导致Vsync不能及时处理#(不高兴) 想不开? 实际开发中性能问题不好复现?这你就可能需要一些工具来帮你检测这种情况. 首先是Android系统自带的工具(4.1之后的版本) ...

  10. leading--Oracle hint

    SQL>  explain plan for select rowid rid from  2   scott.emp e where e.empno >100 and e.empno & ...