CCF- CSP 202209-2 何以包邮? 两种方法 dfs+离散化 满分题解

CCF- CSP 202209-2 何以包邮? 两种方法 dfs+离散化 满分题解

题目链接:202209-2 何以包邮?

思路1(离散化):

  • n最大为30,a最大为104,所以最大价格为3e5
  • 将所有组合的价格映射到f上,从x开始向大进行查找,直到找到第一个大于等于x的价格(存在此组合)
  • 技巧在于求各种组合的价格,也是采用离散化的思想,将每一个价格和组合映射到f上,每次从M开始遍历整个f,找到加入当前price后,此price和之前的组合形成的新组合所对应的值

代码如下:

#include<iostream>
using namespace std;
const int N = 50, M = 3e5 + 10;//M的范围得大
int n,x;
int price[N];//价格
int f[M];//存储离散化后的点
int main()
{
    cin>>n>>x;
    for(int i=1;i<=n;i++)
    {
        cin>>price[i];
    }
    
    //得到各种组合后的价格
    f[0]=1;//初始化
    for(int i=1;i<=n;i++)
    {
        for(int j=M;j>=price[i];j--)
        {
            if(f[j-price[i]])
            {
                f[j]=1;
            }
        }
    }
    
    int out = x;//起始位置
    while(1)
    {
        if(f[out])break;//找到第一个大于等于x的价格
        else
        {
            out++;
        }
    }
    cout<<out<<endl;
    return 0;
}

思路2(dfs不剪枝70分):

  • 对于每本书,都有选和不选两种方案,可以对应一棵完全二叉树
  • 遍历所有书的两种方案,找到最小值,采用dfs算法

70分代码如下:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 50;
int n,x;
int price[N];
int ans = 1e9;
void dfs(int k,int sum)
{
    
    if(sum>=x)
    {
        ans = min(sum,ans);//更新最小值
    }
    if(k>n)
    {
        return;
    }
    dfs(k+1, sum+price[k]);//选择这本书
    dfs(k+1,sum);//不选择这本书
}
int main()
{
    cin>>n>>x;
    for(int i=1;i<=n;i++)
    {
        cin>>price[i];
    }
    dfs(1,0);//从第一本书开始
    cout<<ans<<endl;
}

思路三(dfs+剪枝100分):

  • 在思路二的基础上,对二叉树进行剪枝
  • 剪枝思路:当前节点sum加上剩余节点的所有值之和已经小于x了,进行剪枝
  • 求剩余节点的所有值,可以采用前缀和的思想

代码如下:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 50;
int n,x;
int price[N];//价格
int sum_price[N];//前缀和
int ans = 1e9;
void dfs(int k,int sum)
{
    
    if(sum+sum_price[n]-sum_price[k-1]<x)//sum_price[n]-sum_price[k-1]为剩余节点的所有值的和
    {
        return;
    }
    if(sum>=x)
    {
        ans = min(sum,ans);//更新最小值
    }
    if(k>n)
    {
        return;
    }
    dfs(k+1,sum+price[k]);//选择这本书
    dfs(k+1,sum);//不选择这本书
}
int main()
{
    cin>>n>>x;
    for(int i=1;i<=n;i++)
    {
        cin>>price[i];
        sum_price[i]=sum_price[i-1]+price[i];//前缀和
    }
    dfs(1,0);//从第一本书开始
    cout<<ans<<endl;
}
  • 49
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 24
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值