首页 > 其他分享 >8.19 动态规划

8.19 动态规划

时间:2023-10-05 09:22:06浏览次数:22  
标签:use 背包 int long num 8.19 动态 规划 dp

动态规划

一.动态规划初步

 1.硬币问题 

B3635 硬币问题

需要依次枚举每种硬币能否应用的最大情况,设定用0个硬币时的初始值和一个硬币时的初始值(防止越界),后依次增加每个方案数;

#include<bits/stdc++.h>
using namespace std;
long long dp[10000005];
int main(){
    int n;
    cin>>n;
    dp[0]=0,dp[1]=1,dp[2]=2,dp[3]=3,dp[4]=4,dp[5]=1,dp[6]=2,dp[7]=3,dp[8]=4,dp[9]=5,dp[10]=2,dp[11]=1;
    for(int i=11;i<=n;i++){
        dp[i]=min(min(dp[i-1],dp[i-5]),dp[i-11])+1;//最后加上现在的一个方案
    }
    cout<<dp[n];
    return 0;
}

 

题面:

二.01背包问题

推荐博文---【动态规划】01背包问题 - 弗兰克的猫 - 博客园 (cnblogs.com)

01背包上手题:P2871 [USACO07DEC] Charm Bracelet S (https://www.luogu.com.cn/problem/P2871)

 

改编版训练(初步): P2392 kkksc03考前临时抱佛脚

思路:分别枚举左右脑计算每一科的最小时间(最大一次完成量),即所用时长应为总时长一半,且时长不小于每一道题应用时长。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int x[5],y[1000],num,ans,dp[1000];//x存储每一个学科,y存储每道题的时间
 4 //num表示总时间 ,ans是答案,dp数组存储每一科目所用最大时间 
 5 int main(){
 6     for(int i=1;i<=4;i++){//读入每一科 
 7         cin>>x[i];
 8     }
 9     for(int i=1;i<=4;i++){
10         num=0;
11         for(int j=1;j<=x[i];j++){
12             cin>>y[j];
13             num+=y[j];    //累加 
14         }
15         for(int j=1;j<=x[i];j++){    
16             for(int k=num/2;k>=y[j];k--){//两半脑子,所用时间最大为总时长一半 
17                 dp[k]=max(dp[k],dp[k-y[j]]+y[j]);//且不低于每题所用时间 
18             }//取每次最大所用度 
19         }
20         ans+=num-dp[num/2];//每次最少时间为总时间减去一半的最大时间 
21         memset(dp,0,sizeof dp);
22     }
23     cout<<ans;
24     return 0;
25 }

 改编版(背包问题):P1164 小A点菜

本题与普通背包问题不同的是普通背包问题需要求最优解,此题求共有的方案数。

本题需要考虑三个条件:

1.当前剩余钱数刚好等于当前菜价,直接将方案数加1;

2.当前剩余钱数大于当前菜价,方案总数等于不买这道菜的方案数和买这道菜的方案数之和;

3.当前剩余钱数小于菜价,直接继承上一位的总方案数;

综上,可以设一个dp二维数组,代表前i道菜剩余j元时的方案数。

则代码如下:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int a[1000],dp[10000][10000];
 4 int main(){
 5     int n,m;
 6     cin>>n>>m;
 7     for(int i=1;i<=n;i++)cin>>a[i];
 8     for(int i=1;i<=n;i++){//依次枚举每道菜的方案数 
 9         for(int j=1;j<=m;j++){//当前剩余总钱数,不管多大也不会超过m 
10             if(j==a[i])dp[i][j]=dp[i-1][j]+1;
11             if(j>a[i])dp[i][j]=dp[i-1][j]+dp[i-1][j-a[i]];
12             if(j<a[i])dp[i][j]=dp[i-1][j];
13         }
14     }
15     cout<<dp[n][m];//输出买n道菜时用m元的方案总数 
16 return 0;
17 }

 

 例二:(背包问题)P1802 5 倍经验日 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

首先,看见此题应该直接判断出两种情况并同时列出转移方程:

1.打得过   1.打  dp[ j ] = dp[ j - use[ i ] + win[ i ] ];

       2.不打  dp[ j ] = dp[ j ] + lose[ i ];

2.打不过  dp[ j ] = lose[ i ];

因此,打得过的情况下 j 应大于此时所消耗的 use[ i ] ,反之则小于;

代码如下:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 long long n,x,lose[1005],win[1005],use[1005],dp[1005];
 4 int main(){ 
 5     cin>>n>>x;
 6     for(int i=1;i<=n;i++){
 7         cin>>lose[i]>>win[i]>>use[i];
 8         for(int j=x;j>=use[i];j--){//打得过时
 9             dp[j]=max(dp[j]+lose[i],dp[j-use[i]]+win[i]);//取打和不打的最大值(所获经验最大)
10         }
11         for(int j=use[i]-1;j>=0;j--)dp[j]+=lose[i];//打不过的情况
12     }
13     cout<<dp[x]*5;//五倍经验
14 
15 return 0;
16 }

 

 例三:01背包经典题目:P3273 - TBOJ-J1T2【小花园美化计划】 - TBOJ

 两个方案:1 . 买  1   dp [ j ] = max ( dp [ j ] , dp [ j - v [ j ][ 0 ] ] + b [ i ] ) ;

      2 . 买  2   同上仅是把0换成一

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int m,n,s,b[10005][100],v[10005][100],dp[10005],l;
 4 int main(){
 5     freopen("flower.in","r",stdin);
 6     freopen("flower.out","w",stdout);
 7     ios::sync_with_stdio(0);
 8     cin>>m>>n>>s;
 9     for(int i=1;i<=n;i++){
10         for(int j=1;j<=2;j++){
11             cin>>b[i][j]>>v[i][j];
12         }
13     }
14     for(int i=1;i<=n;i++){
15         for(int j=m;j>=0;j--){//枚举第i盆花用m元时漂亮指数
16             if(j>=v[i][1])dp[j]=max(dp[j],dp[j-v[i][1]]+b[i][1]);
17             if(j>=v[i][2])dp[j]=max(dp[j],dp[j-v[i][2]]+b[i][2]);
18         }
19     }
20     cout<<dp[m]+s;
21     return 0;
22 }

 

    方法:枚举 n 盆花的同时,枚举 m 元钱时各自的方案

 

三.完全背包问题

性质:与 01 背包一样,不过需要多次判断,重点还是找对转移方程

推荐博文:【动态规划】完全背包问题 - 弗兰克的猫 - 博客园 (cnblogs.com)

入门中。。。。

任务一: 将01背包改为完全背包!

修改方法:1.找出区别:一个可以重复选择多个,一个不可以。

·      2.转移公式如果选择多个需要加上乘号。

此法缺点:三重循环,时间复杂度炒鸡大!

代码ing~~:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 long long tim,num,dp[10005000],t[10005000],v[10005000];
 4 int main(){
 5     cin>>tim>>num;
 6     for(int i=1;i<=num;i++)
 7         cin>>t[i]>>v[i];
 8     for(long long i=1;i<=num;i++)
 9         for(long long j=tim;j>=1;j--){
10             for(long long k=0;k<=j/t[i];k++){//注意是j/t[i] 因为时间总量要跟着上面循环的变化而变化 
11                 dp[j]=max(dp[j],dp[j-k*t[i]]+k*v[i]);//注意 t[i]和v[i]要用k倍的 
12             }
13         }
14     
15     cout<<dp[tim];
16 return 0;
17 }

注:原题(会炸!):P1616 疯狂的采药 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

 

 四.多重背包

性质:与完全背包相同,不过每一种物品限定个数(非无限)

本段重点!----自上而下记忆法(用来寻找转移方程)

特殊点:完全背包是与自身横向一行与纵向一列的总数和

 

 这两个背包问题的关键都在于状态转移方程的寻找,如果对于类似的问题没有思路,可以先尝试找出递归解法,然后自上而下的记忆法便水到渠成了。

标签:use,背包,int,long,num,8.19,动态,规划,dp
From: https://www.cnblogs.com/Cathy-zy/p/17643427.html

相关文章

  • C语言之预处理,动态库,静态库
    目录4.1c语言编译过程4.2include4.3define4.4选择性编译4.5静态库4.6动态库4.1c语言编译过程1:预编译将.c中的头文件展开、宏展开生成的文件是.i文件2:编译将预处理之后的.i文件生成.s汇编文件3、汇编将.s汇编文件生成.o目标文件4、链接将.o文件链接成目标文件......
  • 动态规划基础
    动态规划方案数问题例:P1002[NOIP2002普及组]过河卒解题思路参考代码#include<cstdio>typedeflonglongLL;constintN=25;intdx[8]={-2,-2,-1,-1,1,1,2,2};intdy[8]={-1,1,-2,2,-2,2,-1,1};boolcontrol[N][N];LLdp[N][N];intm......
  • 数组动态创建问题
    数组动态创建问题C++较新版本中允许通过变量方式动态创建数组intn;cin>>n;inta[n]={0};但有些ide会提示"表达式必须含有常量值c/c++"问题,可用一下方式消除此问题intn;cin>>n;inta*=newint[n];......
  • 04-共阳数码管的动态显示
    共阳数码管的动态显示代码如下:#include<REGX52.H>voidDisplay_Dynamic();unsignedcharmonth=1;voidDelay_ms(unsignedintxms){ unsignedinti,j; for(i=0;i<xms;i++){ for(j=0;j<299;j++); }}voidDelay(unsignedchart){ while(t--){ //......
  • Linux动态库
    制作动态库(也称为共享库)是将可重用的代码和函数打包成单独的库,可以在多个程序中共享使用。在Linux上制作动态库涉及以下步骤:编写源代码:编写你的代码,并确保它们可以编译为动态库。通常,你需要将代码拆分成多个文件,每个文件对应一个模块或功能。编译源代码:使用合适的编译器(如......
  • 【笔记】P2542 [AHOI2005] 航线规划 答辩做法
    洛谷上是可以过掉的。NFLSOJ上加强数据,还卡常,所以90pts。首先倒着做很好想。对于最终的图,我们可以tarjan缩点然后建树,边权为\(1\),表示一条割边。然后每次连两个点的时候就把树上这一段路径赋值为\(0\)。查询就是树上路径和。这些操作都可以点赋边权然后树剖来做。所以你就得......
  • 近期动态
    2023年10月3日最近在复习计算机基础知识,主要用于面试主要复习的材料有小林code比较深入、易于理解JavaGuide比较广泛、方便速成r2code(主要是codeSheep的技术博文)近期打算在10.10号前,刷完这四个,并且完成相应的笔记整理小林coding计算机网络操作系统mysqlredis......
  • 理论的动态发展完完备与进化:数论Number Theory数域的进化史 与 Infinite Precision无
    InfinitePrecision:(0)数是什么?以有限的数元,度量与表示无限的现象、事物与状态,作为整个数学科学理论的根基。以Binary二进制为例,有{0,1},Constant/Dynamic系统建模上,两种state(状态)?0->1与1->0代表“change变化”?而Decimal十进制,有{0,1,2,3,4,5,6,7,8,9}十种数元,运算符号......
  • [C语言]动态内存分配遇上函数-经典错误纠错
    题目来自nice2016校招笔试题直接完整代码#include<stdio.h>#include<stdlib.h>#include<string.h>voidGetMemory(char*p)//申请内存{ p=(char*)malloc(100);}voidTest(){ char*str=NULL; GetMemory(str); strcpy(str,"helloworld")......
  • Unity性能优化-动态合批
    动态合批也叫动态批处理,是Unity的一种优化技术。对移动的物体使用动态合批后,则Unity不会一个个绘制它们,而是把它们合并为一个批次(Batch),再由CPU把它们一次性提交给GPU进行处理,这样可以减少DrawCall带来的性能消耗,从而提高性能。官方文档:https://docs.unity3d.com/cn/current/Man......