UVA 1412 Fund Management(DP)

题意是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;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值