题目
P5662 [CSP-J2019] 纪念品 - 洛谷 https://www.luogu.com.cn/problem/P5662


思路
- 贪心算法,每次找单位本金最高收益交易,但是不完全对。选择第一个获得100收益,但是本金不足以进行剩余买卖。而舍去第一商品,能完成剩余的两项交易,而收益是105。
- 动态规划,完全背包问题,从少到多计算每个单位本金交易不同数量商品所取得最高盈利。
贪心算法代码
45分,时间复杂度t*nlogn,t天乘以排序
#include <bits/stdc++.h>
using namespace std;
struct souvenir{
int v,//价格
profit;//利润
float x;//单价利润
bool operator < (const souvenir b)const{
return x>=b.x;
}
};
int t,//交易天数
n,//纪念品种类
m,//金币数
d[105][105],//100天,100中商品的盈利价格
ans;
int main(){
freopen("data.cpp","r",stdin);
cin>>t>>n>>m;
for(int i=1;i<=t;i++)
for(int j=0;j<n;j++)cin>>d[i][j];
for(int i=2;i<=t;i++){
vector<souvenir> v;
for(int j=0;j<n;j++){
int profit=d[i][j]-d[i-1][j];
v.push_back(souvenir{d[i-1][j],profit,profit*1.0/d[i-1][j]});
}
sort(v.begin(),v.end());//按照收益率降序排序
/*for(vector<souvenir>::iterator it=v.begin();it!=v.end();it++)cout<<setprecision(3)<<it->x<<"\t";cout<<endl;
for(vector<souvenir>::iterator it=v.begin();it!=v.end();it++)cout<<it->profit<<"\t";cout<<endl;
for(vector<souvenir>::iterator it=v.begin();it!=v.end();it++)cout<<it->v<<"\t";cout<<endl;*/
int m2=m;
for(int j=0;j<n&&m>0;j++)//按收益率完成交易,贪心计算最多收益
if(v[j].profit>0&&m>=v[j].v){
m2+=m/v[j].v*v[j].profit;//增益
m-=m/v[j].v*v[j].v;//减去该交易本金
}
//cout<<i<<":"<<m2<<endl;
m=m2;
}
cout<<m;
return 0;
}
动态规划代码
ac,时间复杂度tnm
状态:每天多少本金交易前几个商品所得最大利润
状态转移:
要么不交易本商品本有的利润
要么购买本商品剩余本金的利润+该商品利润。
#include <bits/stdc++.h>
using namespace std;
int t,//交易天数
n,//商品数
m,//本金
p[101][101],//哪天哪个商品的交易价格
dp[101][10001];//多少本金经1天交易前几个商品后最高盈利
/*
参数1:几个商品 ,参数2:多少本金
for(int i=0;i<n;i++)//每个商品
dp[i][m]=max(dp[i-1][m],dp[i][m-p[t-1][i]]+p[t][i]-p[t-1][i])
1天之内m本金交易i个商品后的最高盈利=
最大(不交易该商品的盈利,买该商品剩余得本金本来所得最高收益+交易该商品所得)
*/
int main(){
//freopen("data.cpp","r",stdin);
cin>>t>>n>>m;
for(int i=1;i<=t;i++)//第几天
for(int j=1;j<=n;j++)//第几个商品
cin>>p[i][j];
for(int tx=2;tx<=t;tx++){//第2天开始交易,逐日计算盈利并本金的变化
memset(dp,0,sizeof(dp));//重新算本金每天的盈利
for(int i=1;i<=n;i++)//两个含义,从递归讲是共几个商品,从商品角度讲是第几个商品
for(int j=0;j<=m;j++){//本金数,每个数都算对应的盈利
dp[i][j]=dp[i-1][j];//确保不选择当前商品的状态正确继承
if(j>=p[tx-1][i])//本金购买商品
dp[i][j]=max(dp[i][j],dp[i][j-p[tx-1][i]]+p[tx][i]-p[tx-1][i]);
}
m+=dp[n][m];//比对完所有商品交易盈利,才得最高的盈利。变成本金
}
cout<<m;
return 0;
}
273

被折叠的 条评论
为什么被折叠?



