UVALive 4048 Fund Management(状压DP)

来源:互联网 发布:沈阳办公软件培训班 编辑:程序博客网 时间:2024/04/27 15:33

题目链接:点击打开链接

【链接为NEERC 2007整套题,该题为其中的F题】

【要不是UVALive4048题目挂了我也不会出此下策Orz】

初步思路是,设dp[i][j]为当前dp到第i天,股票持有状态为j的情况下的最大获得金额。

那么显然枚举前一天的所有交易决策然后取最大就行了。

关键问题在于状态j如何表示。

首先,最多有8种股票,每种最多可以有8手,所以最先考虑的是用一个8位的9进制数表示状态,不过数字太大数组开不了。

由于股票数总和最多为8,故8位9进制数的所有情况中很多种情况都是不可能出现的。(事实上只有最多12870种情况)

可以想到用map数组来表示dp数组,但这样即使是log级别的查询也会导致TLE。

最后想到的是预处理出0~12869对所有可能出现的状态的映射,这样每次查询就可以做到O(1)。

于是就有了代码中那一段dfs预处理

之后就直接从头到尾DP了,由于要输出最优解的方案所以需要记录路径。

由于避免对不必要计算的状态进行计算,故代码中使用的不是直接DP,而是bfs的方式从最开始的状态展开搜索覆盖最优解。

代码如下,虽然一直改来改去导致其可读性变得非常差。。

将就着看吧Orz

#include<bits/stdc++.h>#define eps 1e-8using namespace std;map<long long,int> st;const long long nie[9]={1,9,81,729,6561,59049,531441,4782969,43046721};//预处理 struct vnode{int k;int a[10];int dnxt[10];int unxt[10];};vnode V[13000];int top;int vdfs(long long bitm){if(st.find(bitm)!=st.end())return st[bitm];st[bitm]=top;int pos=top;top++;long long p=bitm;V[pos].k=0;for(int i=0;i<8;i++){V[pos].a[i]=p%9;V[pos].k+=V[pos].a[i];p/=9;}for(int i=0;i<8;i++){if(V[pos].a[i]>0)V[pos].dnxt[i]=vdfs(bitm-nie[i]);else V[pos].dnxt[i]=-1;if(V[pos].k<8&&V[pos].a[i]<8)V[pos].unxt[i]=vdfs(bitm+nie[i]);else V[pos].unxt[i]=-1;}return pos;}void init(){st.clear();top=0;vdfs(0LL);}//预处理结束 bool vis[105][13000];double dp[105][13000];int lst[105][13000];double c;int m,n,k;int S[10],K[10];double P[10][105];char name[10][105];struct node{int i,j;node(int ii=0,int jj=0):i(ii),j(jj){}};void bfs(){memset(vis,0,sizeof(vis));queue<node> q;q.push(node(0,0));dp[0][0]=c;vis[0][0]=true;while(!q.empty()){node p=q.front();q.pop();if(p.i==m)continue;int &b1=p.i,&b2=p.j;if(V[b2].k<k){for(int i=0;i<n;i++){double w=P[i][b1]*S[i];if(V[b2].a[i]<K[i]&&(dp[b1][b2]-w>-eps)){if(dp[b1+1][V[b2].unxt[i]]<=dp[b1][b2]-w){dp[b1+1][V[b2].unxt[i]]=dp[b1][b2]-w;lst[b1+1][V[b2].unxt[i]]=b2;}if(!vis[b1+1][V[b2].unxt[i]]){q.push(node(b1+1,V[b2].unxt[i]));vis[b1+1][V[b2].unxt[i]]=true;}}}}for(int i=0;i<n;i++){double w=P[i][b1]*S[i];if(V[b2].a[i]>0){if(dp[b1+1][V[b2].dnxt[i]]<=dp[b1][b2]+w){dp[b1+1][V[b2].dnxt[i]]=dp[b1][b2]+w;lst[b1+1][V[b2].dnxt[i]]=b2;}if(!vis[b1+1][V[b2].dnxt[i]]){q.push(node(b1+1,V[b2].dnxt[i]));vis[b1+1][V[b2].dnxt[i]]=true;}}}if(dp[p.i+1][p.j]<=dp[p.i][p.j]){dp[p.i+1][p.j]=dp[p.i][p.j];lst[p.i+1][p.j]=p.j;}if(!vis[p.i+1][p.j]){q.push(node(p.i+1,p.j));vis[p.i+1][p.j]=true;}}}void print_ans(){printf("%.2lf\n",dp[m][0]);vector<int> ans;int p=0;for(int i=m;i>=0;i--){ans.push_back(p);p=lst[i][p];}reverse(ans.begin(),ans.end());for(int i=1;i<ans.size();i++){int x=ans[i-1],y=ans[i],j;for(j=0;j<n;j++){if(V[x].unxt[j]==y){printf("BUY %s\n",name[j]);break;}if(V[x].dnxt[j]==y){printf("SELL %s\n",name[j]);break;}}if(j==n)printf("HOLD\n");}}int main(){//freopen("1.txt","r",stdin);//freopen("2.txt","w",stdout);init();bool flag=false;while(scanf("%lf%d%d%d",&c,&m,&n,&k)==4){if(!flag)flag=true;else printf("\n");memset(dp,0,sizeof(dp));for(int i=0;i<n;i++){scanf("%s%d%d",name[i],&S[i],&K[i]);for(int j=0;j<m;j++)scanf("%lf",&P[i][j]);}bfs();print_ans();}}


1 0