题目大意

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. SQL Server 一个简单的游标

    先看一下原表: DECLARE @id INT; DECLARE @name NVARCHAR(100); DECLARE c_department CURSOR FOR SELECT StuID, ...

  2. SQL Server存储过程作业(一)

    创建客房类型表RoomType 创建客房状态表RoomState 创建客房信息表Room 创建结账状态表ResideState 创建客人信息表GuestRecord 编写sql语句 USE maste ...

  3. Entity FrameWork 操作使用详情

    Entity FrameWork 是以ADO.net为基础发展的ORM解决方案. 一.安装Entity FrameWork框架 二.添加ADO.Net实体数据模型 三.EF插入数据 using Sys ...

  4. PAT_A1155#Heap Paths

    Source: PAT A1155 Heap Paths (30 分) Description: In computer science, a heap is a specialized tree-b ...

  5. C#第八节课

    for的穷举迭代.while.do  while using System;using System.Collections.Generic;using System.Linq;using Syste ...

  6. js 中this到底指向哪里?

    其实js的this指向很简单.我们记住下面3种情况. this 指向的是浏览器中的window.代码如下: function fn(){ this.name='yangkun'; this.age=2 ...

  7. [Ynoi2014]不归之人与望眼欲穿的人们

    题目大意: 给定一个序列,每次单点修改一个数,或给定$x$,询问最短的or起来大于等于$x$的区间的长度(不存在输出-1). 解题思路: 在太阳西斜的这个世界里,置身天上之森.等这场战争结束之后,不归 ...

  8. [luogu2576 SCOI2010] 幸运数字 (容斥原理)

    传送门 Description 在中国,很多人都把6和8视为是幸运数字!lxhgww也这样认为,于是他定义自己的"幸运号码"是十进制表示中只包含数字6和8的那些号码,比如68,66 ...

  9. CSS font-style中italic和Oblique有何区别 标签: css字体 2017-01-05 14:42 60人阅读 评论

    *要搞清楚这个问题,首先要明白字体是怎么回事.一种字体有粗体.斜体.下划线.删除线等诸多属性. 但是并不是所有字体都做了这些,一些不常用的字体,或许就只有个正常体,如果你用Italic,就没有效果了~ ...

  10. Bootstrap关于表格

    1.Bootstrap为表格提供了1种基础样式和4种附加样式以及1个支持响应式的表格. ☑  .table:基础表格 ☑  .table-striped:斑马线表格 ☑  .table-bordere ...