题目大意

Frank从个人投资者获得了c美元的资金,可用于m天的投资。
Frank可以对n(n<=8)支股票进行投资。对于每一支股票:都有一个交易上限si,表示一天最多能交易的股数;还有一个上限ki,表示Frank最多可持有的股数。对于所有种类的股票,同样有一个上限k表示Frank可同时持有的最大股数。
股票的交易还满足一下要求:
1>一天最多只能进行一次交易(你也可以不交易);
2>若要对第i支股票进行买进或卖出,只能一次性买或卖Si股;
3>所有的交易都是在Frank有足够的资金的条件下完成的;
4>当m天过去后,Frank的资金必须全部转化为现金,不能放在股票市场里,(m天之内,股票必须全部卖出)。
现在,给出每一支股票的每一天的价格,要求你计算出Frank能回收的资金的最大值,并给出每一天的具体的操作方法。

思路

先考虑考虑暴力。最后一天要把所有资产转化为现金,我们要枚举前一天在各个股票上各投了多少股(我们把它称为状态state),以及剩余的现金量。用股市上的资产加上剩余的现金量便是所求,然后同理枚举前一天的前一天。但是我们发现,天数和state一定时,剩余的现金量愈大,这种情况就越优。于是我们定义DP[day][state]为第day天还未投股时投股状态state时的最大剩余现金量。递归式为:

DP[day][state] = max{operate(DP[day-1][prevState], stock)|operate∈{Buy, Sell, Hold}, operate后prevState==state,P满足}

P=

  1. 0<=eachStockLot<=EachStockLotLimit
  2. 0<=Sum(stockLot)<=TotLotLimit
  3. leftCash>=0

同时满足。

然后按天刷表即可。

各个函数的功能

InitState:将所有满足(1)、(2)的状态都枚举出来。
SetGraph:从递归式中可以看出,我们应当通过该函数设置出所有的BuyNext,SellNext。很多条件限制在SetState中已经满足了,所以我们用map中的count函数便可判断将要生成的状态是否成立了。
DP:根据递归式递推。
Update:在DP中调用,可节省大量重复代码。看看潜在的MaxCash能否进行“放松”,若能,则为后一个MaxCash重新设置其MaxCash值、前继状态编号、操作的股票、和进行的操作。

状态压缩

如何保存state呢?我们发现总股数和每股最多持股数最多只有(1<<3)==8,所以一个股票买的张数4位整数便足够,4*8==32,整数32子节,所以把一个整数每4个字节表示一个股票买的张数,那么一个整数便可以表示出所有股票的状态。这便是十进制状态压缩。

注意

  • 每个状态都要有个编号,否则状态总数约为1<<32,太多了。
  • 分清curS和curID.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <bitset>
#include <cstdarg>
using namespace std;
//#define test const int MAXSTOCK = 8, MAXDAY = 110, MAXID = 20000, INF = 0x3f3f3f3f;
double BeginMoney;
int TotDay, TotStock, LotLimit;
vector<int> State;
map <int, int> Sid;
int IdCnt = 0;
double DImaxcash[MAXDAY][MAXID];//某天某状态进行操作前的最大现金值
int ISbuynextI[MAXID][MAXSTOCK], ISsellnextI[MAXID][MAXSTOCK];
int DIprevI[MAXDAY][MAXID], DIaction[MAXDAY][MAXID], DIdeltaS[MAXDAY][MAXID];
char* Ans[] = { "HOLD","BUY","SELL" }; struct Stock
{
char name[20];
int eachLot, totLotCnt;
double dailyPrice[MAXDAY];
};
Stock Stocks[MAXSTOCK]; void Reset()
{
State.clear();
Sid.clear();
memset(DImaxcash, 0, sizeof(DImaxcash));
memset(ISbuynextI, 0, sizeof(ISbuynextI));
memset(ISsellnextI, 0, sizeof(ISsellnextI));
memset(DIprevI, 0, sizeof(DIprevI));
memset(DIaction, 0, sizeof(DIaction));
memset(DIdeltaS, 0, sizeof(DIdeltaS));
memset(Stocks, 0, sizeof(Stocks));
IdCnt = 0;
} #define SetState(S, s, i) S = (S & (~(0xf<<(i*4))) | ((s)<<(i*4)))
#define ClearState(S, i) (S &= (~(0xf<<(i*4))))
#define GetState(S, i) (((S) >> (i*4)) & 0xf) void PlusState(int &S, int i, int plus)
{
int temp = GetState(S, i) + plus;
SetState(S, temp, i);
} void InitState(int stockCnt, int& temp, int prevTotal)
{
if (stockCnt == TotStock)
{
State.push_back(temp);
Sid[temp] = IdCnt++;
return;
}
for (int i = 0; i <= Stocks[stockCnt].totLotCnt; i++)
{
if (prevTotal + i <= LotLimit)
{
SetState(temp, i, stockCnt);
InitState(stockCnt + 1, temp, prevTotal + i);
ClearState(temp, stockCnt);
}
}
} void SetGraph()
{
for (int id= 0; id < IdCnt; id++)
{
for (int toStock = 0; toStock < TotStock; toStock++)
{
ISsellnextI[id][toStock] = ISbuynextI[id][toStock] = -1;
int temp = State[id];
PlusState(temp, toStock, 1);
if (Sid.count(temp) > 0)
ISbuynextI[id][toStock] = Sid[temp];
if (GetState(State[id],toStock))
{
temp = State[id];
PlusState(temp, toStock, -1);
ISsellnextI[id][toStock] = Sid[temp];
}
}
}
} void Update(int day, int id, int nextID, int toStock, double leftCash, int action)
{
if (leftCash > DImaxcash[day + 1][nextID])
{
DImaxcash[day + 1][nextID] = leftCash;
DIprevI[day + 1][nextID] = id;
DIdeltaS[day + 1][nextID] = toStock;
DIaction[day + 1][nextID] = action;
}
} void DP()
{
for (int i = 0; i <= TotDay; i++)
for (int j = 0; j < IdCnt; j++)
DImaxcash[i][j] = -INF; DImaxcash[0][0] = BeginMoney;
for (int day = 0; day <= TotDay; day++)
for (int curID = 0; curID < IdCnt; curID++)
{
if (DImaxcash[day][curID] == -INF)
continue; for (int toStock = 0; toStock < TotStock; toStock++)
Update(day, curID, curID, 0, DImaxcash[day][curID], 0); for (int toStock = 0; toStock < TotStock; toStock++)
{
if (ISbuynextI[curID][toStock] != -1 && DImaxcash[day][curID] >= Stocks[toStock].dailyPrice[day] * Stocks[toStock].eachLot - 0.001)
{
double leftCash = DImaxcash[day][curID] - Stocks[toStock].dailyPrice[day] * Stocks[toStock].eachLot;
Update(day, curID, ISbuynextI[curID][toStock], toStock, leftCash, 1);
}
if (ISsellnextI[curID][toStock] != -1 && GetState(State[curID], toStock) > 0)
{
double leftCash = DImaxcash[day][curID] + Stocks[toStock].dailyPrice[day] * Stocks[toStock].eachLot;
Update(day, curID, ISsellnextI[curID][toStock], toStock, leftCash, 2);
}
}
}
} void print(int day, int id)
{
if (day == 0)
return;
print(day - 1, DIprevI[day][id]);
if (DIaction[day][id] == 0)
printf("HOLD\n");
else
printf("%s %s\n", Ans[DIaction[day][id]], Stocks[DIdeltaS[day][id]].name);
} int main()
{
//TestBinary();
freopen("c:\\noi\\source\\input.txt", "r", stdin);
bool isFirst = true;
while (~scanf("%lf%d%d%d", &BeginMoney, &TotDay, &TotStock, &LotLimit))
{
Reset();
for (int i = 0; i < TotStock; i++)
{
scanf("%s%d%d", &Stocks[i].name, &Stocks[i].eachLot, &Stocks[i].totLotCnt);
for (int j = 0; j < TotDay; j++)
scanf("%lf", &Stocks[i].dailyPrice[j]);
}
int temp = 0;
InitState(0, temp, 0);
SetGraph();
DP();
if (!isFirst)
printf("\n");
isFirst = false;
printf("%.2f\n", DImaxcash[TotDay][0]);
print(TotDay, 0);
}
return 0;
}

  

POJ3570 Fund Management 动态规划的更多相关文章

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

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

  2. uva1412 Fund Management

    状压dp 要再看看  例题9-17 /* // UVa1412 Fund Management // 本程序会超时,只是用来示范用编码/解码的方法编写复杂状态动态规划的方法 // Rujia Liu ...

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

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

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

    链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

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

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

  6. [SinGuLaRiTy] 动态规划题目复习

    [SinGuLaRiTy-1026] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. [UVA 1025] A Spy in the Metr ...

  7. 7.25 9figting!

    TEXT 87 Fund management基金管理   A Miller's tale 米勒传奇(陈继龙编译) Dec 7th 2006 From The Economist print edit ...

  8. 7.25 8figting!

    TEXT 87 Fund management基金管理   A Miller's tale 米勒传奇(陈继龙编译) Dec 7th 2006 From The Economist print edit ...

  9. DP 题集 2

    关于 DP 的一些题目 String painter 先区间 DP,\(dp[l][r]\) 表示把一个空串涂成 \(t[l,r]\) 这个子串的最小花费.再考虑 \(s\) 字符串,\(f[i]\) ...

随机推荐

  1. 自学Python六 爬虫基础必不可少的正则

    要想做爬虫,不可避免的要用到正则表达式,如果是简单的字符串处理,类似于split,substring等等就足够了,可是涉及到比较复杂的匹配,当然是正则的天下,不过正则好像好烦人的样子,那么如何做呢,熟 ...

  2. 理解list和vector的区别

    原文:http://genwoxuevc.blog.51cto.com/1852984/503337 vector和数组类似,它拥有一段连续的内存空间,并且起始地址不变,因此它能非常好的支持随机存取( ...

  3. html5与css3入门知识点精炼

    <meta name = "keywords" content="…………"/>(网页搜索时要输入的关键字) <meta name = &qu ...

  4. for 循环练习题

    X3 * 6528 = 3X * 8256X为一个数字 填入一个数字 使等式成立 for (var x=1;x<=9&&x>0;x++) { if ((x*10+3)*65 ...

  5. phpmyadmin搭建

    phpadmin配置: 一.phpadmin安装及配置 1.解压phpadmin压缩包,并复制到 /usr/local/apache2/htdocs目录,重命名为dataManage 2.进入data ...

  6. SmartUpload实现文件上传

    (一)SmartUpload组件简介 SmartUpload组件 专门用于实现文件上传及下载的免费组件   (二)SmartUpload组件特点 使用简单:编写少量代码,完成上传下载功能 能够控制上传 ...

  7. 【sqli-labs】 less32 GET- Bypass custom filter adding slashes to dangrous chars (GET型转义了'/"字符的宽字节注入)

    转义函数,针对以下字符,这样就无法闭合引号,导致无法注入 ' --> \' " --> \" \ --> \\ 但是,当MySQL的客户端字符集为gbk时,就可能 ...

  8. 范畴论-一个单子(Monad)说白了不过就是自函子范畴上的一个幺半群而已

    范畴即为结构:包含要素和转化. 范畴为高阶类型. 函子为高阶函数.函子的输入为态射.函子为建立在态射基础上的高阶函数.函子用于保持范畴间映射的结构.态射用于范畴内部的转换. 群为运算规则的约束. 自函 ...

  9. JDBC Druid式link

    准备工作:导入包------druid-1.0.9.jar    src文件夹下放下druid.properties文件 且其中的url和数据库名要配置完备 import JdbcUtils.JDBC ...

  10. Markdown 常用语法总结

    注意:Markdown使用#.+.*等符号来标记,符号后面必须跟上至少跟上 1个空格才有效! Markdown的常用语法 标题 Markdown标题支持两种形式. 1.用#标记 在标题开头加上1~6个 ...