题意是m天n只股票给你买卖,然后要求最后一天结束后不持有任何股票,剩余钱最多,每天只能买和卖一手某种股票。还有各种限制条件,比如总持有股票数不能超过k,每个股票持有手数最多不能超过多少啊。。
看大白书的题,DP思路很好想,就是到第i天手里买了哪几种股票组合以及手数,拥有现金的最多。这样递推到最后一天手里没有股票所拥有的现金就是答案。
首先状态数是多少?书上写的是最多9^8,实际上远远没有那么多,因为每个股票手数之和最大也不超过8,而且股票总数也最多只有8个,我写了个dfs程序算了下,不超过13000种状态。然后状态转移也很好想,但是不好写,因为涉及到这个数字对应哪种状态,的确可以用9进制去写,不过比较麻烦,可以说不是二进制的状态都不好写,因为要转化成那个进制的数字。
学习了用map<vector<int>, int>的写法,话说vector<int>原来自定义了<号么?还是因为int定义了小于号所以vector<int>也相当于定义了?这点还真不太懂,直接dfs暴力枚举每种可能的状态,然后在map里编好号,再保存每个状态的各种可能转移到的状态,这里改了vector<int>就可以直接在map里找,实在方便。代码的思路跟书上没差太多,不过没照抄。
AC代码:
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<ctime>
#include<string.h>
#include<string>
#include<sstream>
#include<bitset>
using namespace std;
#define ll long long
#define eps 1e-4
#define NMAX 200005
#define MOD 1000000009
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI acos(-1)
template<class T>
inline void scan_d(T &ret)
{
char c;
int flag = 0;
ret=0;
while(((c=getchar())<'0'||c>'9')&&c!='-');
if(c == '-')
{
flag = 1;
c = getchar();
}
while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
if(flag) ret = -ret;
}
double price[10][105],c;
int k[10];
char name[10][10];
vector< vector<int> >v;
map<vector<int>, int>mp;
int m,n,K,buy[13000][10],sell[13000][10];
double dp[105][13000];
int pre[105][13000][3];
int sig(double x){return (x>eps) - (x<-eps);}
void dfs(int w, vector<int>& lots, int totlot)
{
if(w == n)
{
lots[n] = totlot;
mp[lots] = v.size();
v.push_back(lots);
return;
}
for(int i = 0; i <= k[w] && i+totlot <= K; i++)
{
lots[w] = i;
dfs(w+1, lots, totlot+i);
}
}
void init()
{
v.clear();
mp.clear();
vector<int>p(n+1);
dfs(0,p,0);
for(int i = 0; i < v.size(); i++)
{
int sum = v[i][n];
for(int j = 0; j < n; j++)
{
buy[i][j] = sell[i][j] = -1;
if(v[i][j] < k[j] && sum < K)
{
vector<int>temp = v[i];
temp[j]++;
temp[n]++;
buy[i][j] = mp[temp];
}
if(v[i][j] > 0)
{
vector<int>temp = v[i];
temp[j]--;
temp[n]--;
sell[i][j] = mp[temp];
}
}
}
}
void print(int day, int state)
{
if(day == 0) return;
print(day-1, pre[day][state][0]);
if(pre[day][state][2] == 0) printf("HOLD\n");
else if(pre[day][state][2] > 0) printf("BUY %s\n",name[pre[day][state][1]]);
else printf("SELL %s\n",name[pre[day][state][1]]);
}
int main()
{
#ifdef GLQ
freopen("input.txt","r",stdin);
// freopen("o4.txt","w",stdout);
#endif // GLQ
while(~scanf("%lf%d%d%d",&c,&m,&n,&K))
{
for(int i = 0; i < n; i++)
{
int pp;
scanf("%s%d%d",name[i],&pp,&k[i]);
for(int j = 0; j < m; j++)
{
scanf("%lf",&price[i][j]);
price[i][j] *= pp;
}
}
init();
for(int i = 0; i <= m; i++)
for(int j = 0; j < v.size(); j++)
{
dp[i][j] = -(1<<30);
}
dp[0][0] = c;
for(int i = 0; i < m; i++)
for(int j = 0; j < v.size(); j++) if(sig(dp[i][j]) >= 0)
{
if(dp[i][j] >= dp[i+1][j])
{
dp[i+1][j] = dp[i][j];
pre[i+1][j][0] = j;
pre[i+1][j][2] = 0;
}
for(int ii = 0; ii < n; ii++)
{
if(sig(dp[i][j]-price[ii][i]) >= 0 && buy[j][ii] != -1 && dp[i+1][buy[j][ii]] < dp[i][j]-price[ii][i])
{
dp[i+1][buy[j][ii]] = dp[i][j] - price[ii][i];
pre[i+1][buy[j][ii]][0] = j;
pre[i+1][buy[j][ii]][1] = ii;
pre[i+1][buy[j][ii]][2] = 1;
}
if(sell[j][ii] != -1 && dp[i+1][sell[j][ii]] < dp[i][j]+price[ii][i])
{
dp[i+1][sell[j][ii]] = dp[i][j] + price[ii][i];
pre[i+1][sell[j][ii]][0] = j;
pre[i+1][sell[j][ii]][1] = ii;
pre[i+1][sell[j][ii]][2] = -1;
}
}
}
printf("%.2lf\n",dp[m][0]);
print(m,0);
}
return 0;
}