CSP历年复赛题-P5662 [CSP-J2019] 纪念品
原题链接:https://www.luogu.com.cn/problem/P5662
题意解读:n件物品,t天每天有不同的价格,类似股票,初始有m金币,每天都可以无限次买卖,问最后最多可以达到多少金币。
解题思路:
考试中一定要学会面向数据编程!
1、对于 10% 的数据,𝑇=1
只有1天的情况下,无论怎么买卖,金币都不会有什么变化,直接输出m就好了。
10分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 105, M = 10005;
int t, n, m;
int main()
{
cin >> t >> n >> m;
if(t == 1) cout << m;
return 0;
}
2、另有𝑇≤100,𝑁=1 的数据,
如果只有一个物品,那么很显然,应该在价格最低点买入,在价格最高点卖出
只需要枚举所有的上升子序列的起点和终点,分别进行买、卖操作,模拟整个过程即可。
25分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 105, M = 10005;
int t, n, m;
int p[N][N];
int main()
{
cin >> t >> n >> m;
for(int i = 1; i <= t; i++)
for(int j = 1; j <= n; j++)
cin >> p[i][j];
if(t == 1) cout << m;
else if(n == 1)
{
int cnt = 0; //持有的物品数
for(int i = 1; i <= t; i++)
{
if(p[i][1] < p[i + 1][1] || i == 1) //如果是阶段性价格最低点
{
//买
cnt = m / p[i][1];
m -= cnt * p[i][1];
//找到连续增长的最大点
int j = i;
while(p[j + 1][1] > p[j][1])
{
j++;
}
//卖
m += cnt * p[j][1];
cnt = 0;
i = j;
}
}
cout << m;
}
return 0;
}
3、另有15%的数据,𝑇=2,𝑁≤100
如果只有两天,要使得总收益最大,必须要在第一天买到最高价值的物品,本质上是一个背包问题!
背包的容量:初始的金币数m
物品的体积:第一天的价格
物品的价值:第二天的价格 - 第一天的价格
每个物品可以买无限次,所以是一个完全背包问题。
40分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 105, M = 10005;
int t, n, m;
int p[N][N];
int f[N][M]; //f[i][j]表示当天用j金币买前i个物品在后一天能获得的最大收益
int main()
{
cin >> t >> n >> m;
for(int i = 1; i <= t; i++)
for(int j = 1; j <= n; j++)
cin >> p[i][j];
if(t == 1) cout << m;
else if(n == 1)
{
int cnt = 0; //持有的物品数
for(int i = 1; i <= t; i++)
{
if(p[i][1] < p[i + 1][1] || i == 1) //如果是阶段性价格最低点
{
//买
cnt = m / p[i][1];
m -= cnt * p[i][1];
//找到连续增长的最大点
int j = i;
while(p[j + 1][1] > p[j][1])
{
j++;
}
//卖
m += cnt * p[j][1];
cnt = 0;
i = j;
}
}
cout << m;
}
else if(t == 2)
{
for(int i = 1; i <= n; i++)
{
for(int j = 0; j <= m; j++)
{
f[i][j] = f[i - 1][j];
if(j >= p[1][i]) f[i][j] = max(f[i][j], f[i][j - p[1][i]] + p[2][i] - p[1][i]);
}
}
cout << m + f[n][m];
}
return 0;
}
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 105, M = 10005;
int t, n, m;
int p[N][N];
int f[M]; //f[j]表示当天用j金币买的物品在后一天能获得的最大收益
int main()
{
cin >> t >> n >> m;
for(int i = 1; i <= t; i++)
for(int j = 1; j <= n; j++)
cin >> p[i][j];
for(int k = 1; k < t; k++) //枚举天
{
memset(f, 0, sizeof(f));
for(int i = 1; i <= n; i++) //枚举物品
{
for(int j = p[k][i]; j <= m; j++) //枚举手头金币数
{
f[j] = max(f[j], f[j - p[k][i]] + p[k + 1][i] - p[k][i]);
}
}
m += f[m];
}
cout << m;
return 0;
}