题目大意

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. A - Word

    Problem description Vasya is very upset that many people on the Net mix uppercase and lowercase lett ...

  2. pinpoint 磁盘不足的坑

    观察 pinpoint hbase 数据存储目录default中各个表的大小 TraceV2 15G ApplicationTraceIndex 15G major_compact的操作目的 合并文件 ...

  3. KVO的使用及底层实现

    1.概念 KVO(Key-Value-Observer)也就是观察者模式,是苹果提供的一套事件通知机制.允许对象监听另一个对象特定属性的改变,并在改变时接收到事件,一般继承自NSObject的对象都默 ...

  4. 【PostgreSQL-9.6.3】函数(2)--字符型函数

    在上一篇博文中我们交流了数值型函数,这篇我们将讨论PostgreSQL中的字符型函数. 1. reverse(string) reverse函数可以将string字符串的字母显示顺序颠倒. test= ...

  5. oracle从入门到精通复习笔记

    为方便大家跟着我的笔记练习,为此提供数据库表文件给大家下载:点我下载 描述一个表用 desc employees过滤重复的部门 select distinct department_id from e ...

  6. AI:PR的数学表示-传统方法PR

    前言: 接上一篇:AI:模式识别的数学表示 在图像处理PR领域,相对于ANN方法,其他的方法一般称为传统方法.在结构上,几乎所有的PR方法都是可解释的.且任一传统方法,在一定约束下,可以转换为SV近邻 ...

  7. 时序分析:串匹配—Brute-Force算法

    在使用KMP算法之前,使用了BF算法用于串匹配:原文链接已无法查找.....        设有主串s和子串t,子串t的定位就是要在主串s中找到一个与子串t相等的子串.通常把主串s称为目标串,把子串t ...

  8. 阿里巴巴矢量库IconFont__使用小录

    使用阿里巴巴矢量库方法虽然不难,但本人记性不好,遂在次记录几笔 阿里巴巴矢量库地址:http://www.iconfont.cn/plus 阿里巴巴矢量库图标好处: 1:图标矢量化 2:自己总结:ic ...

  9. 小程序viewflex布局的对齐不对的问题

    index.wxml: <view class="container"> <view class="nav-container"> &l ...

  10. react功能实现-数组遍历渲染

    在react中如何将一个数组遍历,并且逐个渲染在页面上? 1.在jsx渲染中,如果这个变量是一个数组,则会展开这个数组的所有成员. var arr = [ <h1>Hello world! ...