首页 > 其他分享 >背包之专题

背包之专题

时间:2023-07-16 15:33:23浏览次数:33  
标签:背包 15 硬币 int 专题 dp dis

P1282 多米诺骨牌 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

第一题 一道思维题

 设dis=a[i]−b[i]

f[i][j+dis+N]=min(f[i][j+dis+N],f[i−1][j+N]);//不反转

f[i][j+dis+N]=min(f[i][j+dis+N],f[i−1][j+N]+1);//反转

f[i][j+N]=min(f[i−1][j−dis+N],f[i−1][j+dis+N]+1);


#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5,mod=998244353;
typedef long long LL;
typedef unsigned long long ULL;
int b[N],c[N],n;
LL dp[N];
int main()
{
    //freopen("perm.in","r",stdin);
    //freopen("perm.out","w",stdout);
    int T;
    cin>>T;
    while(T--)
    {
        memset(dp,0,sizeof(dp));
        int flag=1;
        cin>>n;
        cin>>b[1];
        for(int i=2;i<=n;i++)
        {
            scanf("%d",&b[i]);
            if(b[i]>b[i-1]||b[i]<1||b[i]>n)
                flag=0;
        }
        cin>>c[1];
        for(int i=2;i<=n;i++)
        {
            scanf("%d",&c[i]);
            if(c[i]<c[i-1]||c[i]<1||c[i]>n||c[i]<b[i])
                flag=0;
            if(c[i]>c[i-1]&&b[i]<b[i-1])
                flag=0;
        }
        if(b[1]!=c[1])
            flag=0;
        if(flag==0)
        {
            cout<<0<<endl;
            continue;
        }
        else
        {
            
            int num=1;
            dp[1]=1;
            for(int i=2;i<=n;i++)
            {
                if(b[i]==b[i-1]&&c[i]==c[i-1])
                    dp[i]=dp[i-1]*(c[i]-b[i]+1-num)%mod;
                else if((b[i]==b[i-1]&&c[i]>c[i-1])||(b[i]<b[i-1]&&c[i]==c[i-1]))
                    dp[i]=dp[i-1];
                num++;
            }
            printf("%lld\n",dp[n]);
        }
    }
    return 0;
}

https://www.luogu.com.cn/problem/P2732

一道有意思的题目

一眼望去,背包问题,但是编号和组合的数值都不好存储

看似无从下手,但是再认真观察数据

发现最多只有五种商品,且最多单品购买数不超过五个

由此灵光一现   多维dp 多维dp 多维dp

好像可以做

于是设计状态 dp[i][j][k][l][p] 我们令 dp[i][j][k][l][o] 代表当第一种物品有 i 个,第二种物品有 j 个。。。时的最小花费。

于是就得到了一个五维的01背包

代码并不难写

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5;
struct node{
    int s,k[8],p;
}a[N];
int n,m,f[15][15][15][15][15],b[N],cnt,v[15];
int main()
{
    cin>>m;
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&a[i].s);
        for(int j=1;j<=a[i].s;j++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if(b[x]==0) b[x]=++cnt;
            a[i].k[b[x]]=y;
        }
        scanf("%d",&a[i].p);
    }
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if(b[x]==0) b[x]=++cnt;
        v[b[x]]=y;
        m++;
        a[m].s=1;a[m].k[b[x]]=1;a[m].p=z;
    }
    memset(f,127,sizeof(f));
    f[0][0][0][0][0]=0;
    for(int ki=1;ki<=m;ki++)
     for(int i=a[ki].k[1];i<=v[1];i++)
      for(int j=a[ki].k[2];j<=v[2];j++)
       for(int l=a[ki].k[3];l<=v[3];l++)
        for(int k=a[ki].k[4];k<=v[4];k++)
         for(int r=a[ki].k[5];r<=v[5];r++)
          f[i][j][l][k][r]=min(f[i][j][l][k][r],f[i-a[ki].k[1]][j-a[ki].k[2]][l-a[ki].k[3]][k-a[ki].k[4]][r-a[ki].k[5]]+a[ki].p);
    cout<<f[v[1]][v[2]][v[3]][v[4]][v[5]]<<endl;
    return 0;
}

 

 
P2851 [USACO06DEC] The Fewest Coins G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 这题的题意表述比较 难以描述,比较奇怪 简而言之 即交易涉及的硬币要越少越好 给你 n 种硬币类型,每种硬币类型 vi​ 买家有 ci​ 个,卖家有无限个,买家要买一个 m 元的东西(卖家可以找零),买家问你双方之间交流的硬币个数(指买家用的硬币数 + 卖家找零的硬币数)最少为多少个?

其它题解里面没有详细说明为什么这个题是多重背包+完全背包,这里解释一下。

首先我们来看一下背包都有哪些类型:

  1. 01背包:每个物品可以选也可以不选,如果选只能选1个,一般用dp实现;

  2. 部分背包:每个物品可以选也可以不选,如果选可以全选或者只选择其中的一部分,用贪心就能实现;

  3. 完全背包:每个物品可以选0个,1个,2个,……,无穷多个;

  4. 多重背包:每个物品可以选0个,1个,2个,……,n 个(n 一般会在题目中给出),常常用二进制优化拆分为01背包实现。

回到这道题,我们发现,FJ给钱的时候,他可以使用每一种面额的硬币,而且第 i 种硬币可以选择 1,2,3,⋯ ,1,2,3,⋯,ci​ 个,所以dp FJ给钱的过程用的是多重背包的算法。注意在二进制拆分的时候,不仅钱数要乘以计数器,花费的硬币也要乘以计数器,本人就因为这个问题没有一次AC。如果对二进制拆分不太熟悉,可以看一下宝物筛选那题。

当店主找钱的时候,同样也可以使用所有面额的硬币,但是题目中说店主有无穷多硬币,这不就是完全背包吗?我们枚举店主找的钱,两次dp即可

#include<bits/stdc++.h>
using namespace std;
const int N=1e7+5;
int n,m,v[N],w[N],f[N],dp[N],ans=0x3f3f3f3f,maxx=-10000,sum;
int main()
{
    //freopen("P2851.in","r",stdin);
    //freopen("P2851.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&v[i]);
        maxx=max(maxx,v[i]*v[i]);
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&w[i]); 
        sum=sum+v[i]*w[i];
    }
    if(sum<m)
    {
        cout<<"-1"<<endl;
        return 0;
    }
    memset(f,0x3f,sizeof(f));
    memset(dp,0x3f,sizeof(dp));
    f[0]=dp[0]=0;
    for(int i=1;i<=n;i++)
        for(int j=v[i];j<=maxx;j++)
            f[j]=min(f[j],f[j-v[i]]+1);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=w[i];j<<=1)
        {
            for(int k=m+maxx;k>=j*v[i];k--)
                dp[k]=min(dp[k],dp[k-j*v[i]]+j);
            w[i]-=j;
        }
        if(w[i])for(int j=m+maxx;j>=w[i]*v[i];j--)  dp[j]=min(dp[j],dp[j-w[i]*v[i]]+w[i]);
    }
    for(int i=m;i<=m+maxx;i++)
        ans=min(ans,dp[i]+f[i-m]);
    if(ans==0x3f3f3f3f) cout<<"-1"<<endl;
    else printf("%d\n",ans);
    return 0;
}

P1858 多人背包 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

背包九讲

来分享一下思路.

题解里都说是裸的此类问题,并没有给出解释。

(给出的解释也大多是背包九讲里的一些抽象定义

本题为01背包的前k优解问题 

可以考虑再一维数组再加一维记录当前状态下的前k优解

根据无后效性原则,可以得到成立

 

很容易发现,我们需要记录用其他物品来填充背包是否能得到更优解.

因此我们需要记录一个变量c1表示体积为j的时候的第c1优解能否被更新.

再去记录一个变量c2表示体积为j-v[i]的时候的第c2优解.

#include<bits/stdc++.h>
using namespace std;
int f[5005][55],ans=0;
int k,v,n,w[205],c[205],t[55];
int main()
{
    memset(f,128,sizeof(f));
    scanf("%d%d%d",&k,&v,&n);
    for (int i=1;i<=n;i++) 
        scanf("%d%d",&w[i],&c[i]);
    f[0][1]=0;
    for (int i=1;i<=n;i++)
        for (int j=v;j>=w[i];j--)
        {
            int t1=1,t2=1,t[60],len=0;
            while (t1+t2<=k+1)
            {
                if (f[j][t1]>f[j-w[i]][t2]+c[i]) 
                    t[++len]=f[j][t1++];
                else   t[++len]=f[j-w[i]][t2++]+c[i];
            }
            for (int K=1;K<=k;K++) f[j][K]=t[K];
        }
    for (int i=1;i<=k;i++) ans+=f[v][i];
    printf("%d",ans);
    return  0;
}

 

 

标签:背包,15,硬币,int,专题,dp,dis
From: https://www.cnblogs.com/mingloch/p/17557875.html

相关文章

  • 【专题】2022中国工业机器人市场研究报告PDF合集分享(附原数据表)
    报告链接:https://tecdat.cn/?p=33224本报告合集将基于中国工业产业升级和智能制造的背景,通过对供应端市场和产业链的分析,结合投资视角,探讨工业机器人企业如何增强自身竞争力,推动中国工业产业发展,为企业带来新的增长和转型机会,并从而思考中国工业机器人行业的现状和未来趋势。在......
  • 【专题】2022年中国工业机器人市场白皮书报告PDF合集分享(附原数据表)
    报告链接:https://tecdat.cn/?p=33224本报告合集将基于中国工业产业升级和智能制造的背景,通过对供应端市场和产业链的分析,结合投资视角,探讨工业机器人企业如何增强自身竞争力,推动中国工业产业发展,为企业带来新的增长和转型机会,并从而思考中国工业机器人行业的现状和未来趋势。在......
  • Scrapy 专题
    安装scrapy-pipinstallscrapy创建项目并创建spider,跑起来-scrapystartprojectscrapy_demo1-cdscrapy_demo1-scrapygenspiderbaidubaidu.com-scrapycrawlbaidu报错记录-AttributeError:module‘OpenSSL.SSL’hasnoattribute‘SSLv3_METHO......
  • CTFer成长记录——CTF之Web专题·初识反序列化
    一、题目链接http://122.114.252.87:1110/index2.php前置知识:序列化与反序列化序列化是将变量转换成可保存或传输的字符串,实现函数是:serialize();反序列化是:将字符串转换成变量,是一个逆过程。实现的函数式:unserialize();序列化:上面的结果是对一个对象的打印,后面是序列化......
  • 7.14 海高集训 DP 专题 2
    出题人:\(\text{D}\color{red}\text{eaphetS}\)#A.[NOIP2012提高组]开车旅行倍增优化dp。这题难就难在预处理。首先预处理出A和B每个人从一个城市出发的目标是哪个城市。可以用平衡树找一个点的前驱和后继,或者双向链表。我当然选择了最偷懒的set。(ps:这里如果用set......
  • 算法-背包问题
    01背包问题dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);(j>=w[i])一维化(由于递推关系i只和i-1有关,可进行空间压缩,遍历j时需要逆序遍历)for(inti=0;i<=n;i++){for(intj=target;j>=w[i];j--){dp[j]=max(dp[j],dp[j-w[i]]+v[i]);}}完全背包问题商品不限......
  • 2023 长郡暑期集训 DAY-2 数学专题笔记
    2023长郡暑期集训DAY-2数学质数和约数质数是指除了\(1\)和它本身之外没有其他因数的自然数。质数判定判定单个自然数是否为质数,可以使用试除法,在这里不多描述。boolis_prime(intn){if(n<2)return0;//如果n小于2,不是质数,返回0for(inti=2;i<=n......
  • 【专题】保险行业数字化洞察白皮书报告PDF合集分享(附原数据表)
    报告链接:https://tecdat.cn/?p=33203原文出处:拓端数据部落公众号近年来,"养老"、"三胎政策"、"医疗成本"等一系列备受关注的民生话题,使得保险服务备受瞩目,并逐渐渗透到每个人的生活中。自2020年以来,由于多种因素的影响,人们对健康的意识不断提高,这正在重新塑造中国消费者对保险的......
  • 【专题】2022年中国跨境电商行业研究报告PDF合集分享(附原数据表)
    报告链接:http://tecdat.cn/?p=32044近年来,我国的跨境电子商务发展迅速,在过去五年中,其贸易额增长率达到了16.2%,已经成为稳定对外贸易的一支重要力量(查看文末了解报告PDF版本免费获取方式)。一方面,随着跨境电子商务的发展,跨境电子商务的监管政策得到了进一步的改善,跨境电子商务的规......
  • 实时社群技术专题(二):百万级成员实时社群技术实现(消息系统篇)
    本文由网易云信资深服务器开发工程师曹佳俊分享,原题“深度剖析“圈组”消息系统设计|“圈组”技术系列文章”,为了提升内容品质,本文有修订和删节。1、引言鉴于实时社群产品Discord在IM垂直应用领域的爆火,类似的需求越来越多,云信的“圈组”就是针对这种应用场景的技术产品。......