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;
}

 

posted @ 2024-06-12 14:32  五月江城  阅读(66)  评论(0编辑  收藏  举报