poj3570 Fund Management

Description

Frank is a portfolio manager of a closed-end fund for Advanced
Commercial Markets (ACM). Fund collects money (cash) from individual
investors for a certain period of time and invests cash into various
securities in accordance with fund’s investment strategy. At the end
of the period all assets are sold out and cash is distributed among
individual investors of the fund proportionally to their share of
original investment.

Frank manages equity fund that invests money into stock market. His
strategy is explained below.

Frank’s fund has collected c US Dollars (USD) from individual
investors to manage them for m days. Management is performed on a day
by day basis. Frank has selected n stocks to invest into. Depending on
the overall price range and availability of each stock, a lot size was
chosen for each stock — the number of shares of the stock Frank can
buy or sell per day without affecting the market too much by his
trades. So, if the price of the stock is pi USD per share and the lot
size of the corresponding stock is si, then Frank can spend pisi USD
to buy one lot of the corresponding stock for his fund if the fund has
enough cash left, thus decreasing available cash in the fund. This
trade is completely performed in one day.

When price of the stock changes to p′i later, then Frank can sell this
lot for p′isi USD, thus increasing available cash for further trading.
This trade is also completely performed in one day. All lots of stocks
that are held by the fund must be sold by the end of the fund’s
period, so that at the end (like at the beginning) the fund is holding
only cash.

Each stock has its own volatility and risks, so to minimize the
overall risk of the fund, for each stock there is the maximum number
of lots ki that can be held by the fund at any given day. There is
also the overall limit k on the number of lots of all stocks that the
fund can hold at any given day.

Any trade to buy or sell one lot of stock completely occupies Frank’s
day, and thus he can perform at most one such trade per day. Frank is
not allowed to buy partial lots if there is not enough cash in the
fund for a whole lot at the time of purchase.

Now, when fund’s period has ended, Frank wants to know what is the
maximum profit he could have made with this strategy having known the
prices of each stock in advance. Your task is to write a program to
find it out.

It is assumed that there is a single price for each stock for each day
that Frank could have bought or sold shares of the stock at. Any
overheads such as fees and commissions are ignored, and thus cash
spent to buy or gained on a sell of one lot of stock is exactly equal
to its price on this day multiplied by the number of shares in a lot.

Input

The first line of the input file contains four numbers — c, m, n, and
k. Here c (0.01 ≤ c ≤ 100 000 000.00) is the amount of cash collected
from individual investors up to a cent (up to two digits after decimal
point); m (1 ≤ m ≤ 100) is the number of days in the fund’s lifetime;
n (1 ≤ n ≤ 8) is the number of stocks selected by Frank for trading; k
(1 ≤ k ≤ 8) is the overall limit on the number of lots the fund can
hold at any time.

The following 2n lines describe stocks and their prices with two lines
per stock.

The first line for each stock contains the stock name followed by two
integer numbers si and ki. Here si (1 ≤ si ≤ 1 000 000) is the lot
size of the given stock, and ki (1 ≤ ki ≤ k) is the number of lots of
this stock the fund can hold at any time. Stock name consists of 1 to
5 capital Latin letters from “A” to “Z”. All stock names in the input
file are distinct.

The second line for each stock contains m decimal numbers separated by
spaces that denote prices of the corresponding stock for each day in
the fund’s lifetime. Stock prices are in range from 0.01 to 999.99
(inclusive) given up to a cent (up to two digits after decimal point).

Cash and prices in the input file are formatted as a string of decimal
digits, optionally followed by a dot with one or two digits after a
dot.

Output

Write to the output file m + 1 lines.

On the first line write a single decimal number — the precise value
for the maximal amount of cash that can be collected in the fund by
the end of its period. The answer will not exceed 1 000 000 000.00.
Cash must be formatted as a string of decimal digits, optionally
followed by a dot with one or two digits after a dot.

On the following m lines write the description of Frank’s actions for
each day that he should have made in order to realize this profit.
Write BUY followed by a space and a stock name for buying a stock.
Write SELL followed by a space and a stock name for selling a stock.
Write HOLD if nothing should have been done on that day.

考虑如何压缩状态,也就是要保存9个和不超过9非负整数。如果直接用九进制数保存的话,【直接开数组开不下,因为有很多无用状态,可以用map保存】会因为频繁的编码解码而超时。
可以借鉴NOIP2013华容道(见【这里】)的做法,预处理出所有状态并编号,再预处理出他们之间的转移,这样dp时的转移省去了重复枚举,就是O(1)的了。

#include
#include
#include
#include
#include
using namespace std;
const int mx_sta=20010;
const double eps=1e-5;
map<vector<int>,int> id;
vector<int> sta[mx_sta],now;
char name[10][10];
int m,n,k,num[10],mx_k[10],sta_tot,buy[mx_sta][10],sell[mx_sta][10],
pre_sta[110][mx_sta],opt[110][mx_sta];
double c,dp[110][mx_sta],prc[10][110];
void in()
{
    int i,j;
    scanf("%lf%d%d%d",&c,&m,&n,&k);
    for (i=0;iscanf("%s%d%d",name[i],&num[i],&mx_k[i]);
        for (j=0;jscanf("%lf",&prc[i][j]);
    }
}
void dfs(int p,int tot)
{
    int i;
    if (p==n)
    {
        sta_tot++;
        id[now]=sta_tot;
        sta[sta_tot]=now;
        return;
    }
    for (i=0;i<=mx_k[p]&&i+tot<=k;i++)
    {
        now[p]=i;
        dfs(p+1,tot+i);
    }
}
void make_sta()
{
    int i;
    for (i=0;i0);
    dfs(0,0);
}
void make_trans()
{
    int i,j,temp;
    for (i=1;i<=sta_tot;i++)
    {
        vector<int> v=sta[i];
        temp=0;
        for (j=0;jfor (j=0;jif (v[j]if (v[j])
            {
                v[j]--;
                sell[i][j]=id[v];
                v[j]++;
            }
        }
    }
}
void upd(int p,int s1,int s2,double now,int op)
{
    if (now>dp[p+1][s2])
    {
        dp[p+1][s2]=now;
        pre_sta[p+1][s2]=s1;
        opt[p+1][s2]=op;
    }
}
void solve()
{
    int i,j,k;
    double x,y,z;
    memset(dp,-2,sizeof(dp));
    dp[0][1]=c;
    for (i=0;ifor (j=1;j<=sta_tot;j++)
      {
        x=dp[i][j];
        upd(i,j,j,x,0);
        for (k=0;kif (buy[j][k]&&x-prc[k][i]*num[k]>=-eps)
              upd(i,j,buy[j][k],x-prc[k][i]*num[k],k+1);
            if (sell[j][k])
              upd(i,j,sell[j][k],x+prc[k][i]*num[k],-k-1);
        }
      }
}
void prt(int p,int s)
{
    if (p==0) return;
    prt(p-1,pre_sta[p][s]);
    if (opt[p][s]==0) printf("HOLD\n");
    else
    {
        if (opt[p][s]>0)
          printf("BUY %s\n",name[opt[p][s]-1]);
        else
          printf("SELL %s\n",name[-opt[p][s]-1]);
    }
}
void out()
{
    printf("%.2f\n",dp[m][1]);
    prt(m,1);
}
int main()
{
    in();
    make_sta();
    make_trans();
    solve();
    out();
}

你可能感兴趣的:(动态规划,poj)