XDOJ(智慧平台)--分配宝藏(用动态规划dp算法解决)(C语言)

article/2025/9/13 8:36:07

------------------------------------------------------------
作为西电渣渣,这是我第一次接触需要一些很明确的算法的题目。

第一次博客写废话较多hhh,可以直接到下面看分析

我在昨天晚上和舍友一起肝这道题,肝了一个晚上都没有解决,甚至没有一个很明确的思路。以至于躺在床上都想着怎么写这道题 (毕竟智慧平台上都会出现的题目,难道期末考试不会考吗) 于是来社区看看有没有西电学长 (其实更希望是学姐) 这里推一推学长的博客 XDU-分配宝藏。

但是本人看着稍微有点复杂的代码就头疼,于是去b站找了dp算法的视频动态规划DP0-1背包,看了一半恍然大悟(假的)写出来一个递归函数交上去,发现一半的例子都超时了(泪目)。看完视频才知道dp算法是怎么样写的。
在这里插入图片描述
然后就这样心血来潮,写下这篇博客。
本文章(大概、或许、可能)算是视频和学长博客的结合吧。
------------------------------------------------------------

内容

一. Dynamic Programming (DP算法)
二. 举例(斐波那契数列,0-1背包)
三. 分配宝藏

------------------------------------------------------------

一、Dynamic Programming (DP算法)

DP,听起来挺高级的一个东西,我第一次接触是在洛谷上,但是当时感觉学这玩意还早,就忽视了它,直到我在XDOJ上遇到了它,就有了这篇博客…
DP,中文名译为动态规划,是求解决策过程最优化的过程。各个阶段采取的决策,一般来说是与时间有关的,决策依赖于当前状态,又随即引起状态的转移,一个决策序列就是在 变化的状态中 产生出来的,故有“动态”的含义。(参考 百度百科—动态规划)
下面将直接用例子来说明dp算法。

二、举例(斐波那契数列,0-1背包)

例1. 斐波那契数列

众所周知,斐波那契数列是这样的:
F(0)=1
F(1)=1
F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)
实际上,这个公式就是一个递归的思路,从我们需要求的那个值逐个归回到F(0)和F(1)
由这个公式我们可以写出一个递归函数,其中递归结束的标志是n=0或n=1.

int F(int n){int res;if(n<2) res=1;else res=F(n-1)+F(n-2);return res;
}
//再简化一下可以写成这样
int F(int n){return n<2?1:F(n-1)+F(n-2);
}

又众所周知,函数调用需要额外的空间(栈)来完成,在调用次数很多的情况下会降低程序效率,并且递归调用可能会导致大量的重复计算。所以我们需要把这个递归函数改造成一个效率更高的形式。
可以看到,递归是从我们要的F(n)一直计算到F(0)和F(1),然后再返回到F(n)。在这个过程中,程序在不断地分配空间,降低效率,那我们该怎么改才能提高效率呢?

举个栗子,在Minecraft中,有一处悬崖,附近有一扇门,而门的钥匙落在了悬崖底部,Steve需要取钥匙开门。他有两种方法,一个是递归,一个是dp

递归意味着他从悬崖下去,但他不知道悬崖的高度,因此需要不断地造梯子,爬下来,再返回,来完成这个任务。

dp,真是个好东西。它将Steve传送到了悬崖的底部,并且告诉他悬崖的高度。这个时候,Steve只需要造一定数量的梯子直接搭上去完成任务。(咳咳,这个例子可能有点离谱,但是无伤大雅,dddd)

按照这个想法,递归就相当于从高层走向底层,再返回高层;dp就是从底层打基础到高层,效率更高。
那如何打基础呢?(再回到斐波那契数列)
我们知道当n>2的时候,F(n)=F(n-1)+F(n-2),一直到F(0)和F(1),而F(0)和F(1)就是最基础的基础。(这个时候有小伙伴就要说了,递归函数不也有这个基础吗?答:不要在意这些细节~)dp就是要从基础入手,又又众所周知,要求F(n),就要把F(n-1)到F(0)全部求一遍,那就求呀。由此我们可以写出这么一段代码:

int F[10000];					//数组多大无所谓,只要够用就行
F[0]=F[1]=1;					//初始化F[0]和F[1]
for(int i=2;i<=n;i++)        	//从F[2]开始到F[n]F[i]=F[i-1]+F[i-2];			//套公式//改写成函数
int Fib(int n){int F[10000]={1,1};for(int i=2;i<=n;i++)F[i]=F[i-1]+F[i-2];return F[n];
}

然后,dp这个方法就写完了,然后可能有的小伙伴就懵了,直呼就这?
没错,就这,我们要的F[n]就出来了。
(这时候我突然想起,在刚学递归的时候,其实就接触到了这样简单的dp)
实际上dp算法就像学长@西电蔡徐坤所说的记忆化搜索一样,取之前已经计算过的值,效率更高。
这时候就有小伙伴说了,那递归岂不是一无是处,当然不是了,在很多算法中,有递归做得到而dp做不到的地方,以后或许能够接触到

例2. 0-1背包问题

做完一维的,这个时候再来个二维岂不妙哉~
在这里插入图片描述
如图所示,这就是一个经典的0-1背包问题。
我们设V为背包价值,k为能偷的物品数量,w为背包容量,wi 为第 i 件物品的重量,vi 为第i件物品的价值,则有V=V( k , w )。
在这题中,我们要求的就是V( 4 , 8 )。我们选择从第k件(也就是第四件)开始偷,然后是k-1,k-2 … 2,1件。

从第4件物品开始,我们可以选择偷和不偷。
①.如果选择偷,那么V( 4 , 8 )=V( 4 - 1 , 8 - w4 ) + v4=V( 3 , 3 ) + 8
②.如果选择不偷,则V( 4 , 8 )=V( 4 - 1 , 8 )=V( 3 , 8 )

取①的结果V( 3 , 3 ) + 8
③.发现这个时候的 w(背包容量)< w3,因此只能选择不偷,所以V( 3 , 3 ) + 8=V( 2 , 3 ) + 8
取②的结果V( 3 , 8 )
④.选择偷,那么V( 3 , 8 )=V( 3 - 1 , 8 - w3 ) + v3=V( 2 , 4 ) + 5
⑤.选择不偷,则V( 3 , 8 )=V( 3 - 1 , 8 )=V( 2 , 8 )

••••••
这样推下去,我们可以得到这样的一个简单公式
在这里插入图片描述
而我们要求的应该是最大值,再加上背包容量不够的情况,得到状态转移方程

在这里插入图片描述
看到这里各位小伙伴是不是就可以写一个递归函数出来了,这里我就不再写了(懒)。
那这个递归结束的标志应该是什么呢?
不难想到,当能偷的物品数量为0或者背包剩余容量为0时,递归就该结束了。
因此V( k , 0 )=V( 0 , w )≡0
可以得到这么一个表格
在这里插入图片描述
由此按照例1的思想,是不是就直接能写出代码呢?
这里给出代码片段,剩下的交给小伙伴们自己写出来。

int v[5][9]={0};					
int w[]={0,2,3,4,5};
int v[]={0,3,4,5,8};
for(int k = 1; k <= 4; k++)						//k表示第k件物品for(int W = 1;W <= 8; W++){					//W表示背包剩余容量为Wif(w[i]>W)								//物品重量大于背包剩余容量,不偷v[k][W]=v[k-1][W];else									//否则,从偷和不偷中选出最大值v[k][W]=max( v[k-1][W] ,v[k-1][W-w[k]]+v[k] );//max函数自己写,或者用a?b:c表达式}											//v[4][8]就是要的答案

三、分配宝藏

事件的导火索可不能忘了

标题
分配宝藏
类别
综合
时间限制
2s
内存限制
256Kb
问题描述
两个寻宝者找到一个宝藏,里面包含n件物品,每件物品的价值分别是W[0],W[1],…W[n-1]。
SumA代表寻宝者A所获物品价值总和,SumB代表寻宝者B所获物品价值总和,请问怎么分配才能使得两人所获物品价值总和差距最小,即两人所获物品价值总和之差的绝对值|SumA - SumB|最小。

输入说明
输入数据由两行构成:
第一行为一个正整数n,表示物品个数,其中0<n<=200。
第二行有n个正整数,分别代表每件物品的价值W[i],其中0<W[i]<=200。

输出说明
对于每组数据,输出一个整数|SumA-SumB|,表示两人所获物品价值总和之差的最小值。

输入样例
4
1 2 3 4

输出样例
0

题目分析
这道题和例题2很像,但唯一不同的就是,物品的重量相当于价值。
题目要求A与B之差的绝对值最小,而物品总价值时固定的,因此将背包容量设为sum/2。

下面直接给出我的代码(尽量用代码里的注释解释代码)

#include<stdio.h>
int W[201], sum, dp[201][20001];	//[201]是便于将物品从1开始编号//[20001]同理
int max(int a,int b);
int main(void)
{int n, i, j, sumA;				//假设A得到的永远是较少的那个scanf( "%d", &n);for(i = 1; i <= n; i++){	i代指第i个物品scanf( "%d", &W[i] );sum += W[i];}for(i = 1; i <= n; i++){if (W[i] > sum/2){			//如果物品某个价值大于总价值的一半,其余物品将给A,不需要再计算dp[n][sum/2] =sum-W[i];break;}for(j = 1; j <= sum/2; j++){//j分别代指第i个物品和背包剩余容量if(W[i] > j) 			//同样的,物品重量大于背包剩余容量,不偷dp[i][j] = dp[i-1][j];else dp[i][j] = max( dp[i-1][j] , dp[i-1][j-W[i]] + W[i]);}}sumA = dp[n][sum/2];//个人比较喜欢单一出口printf("%d\n", sum - 2 * sumA);//因为A总是得到较少的那个,不需要再加上绝对值return 0;
}
int max(int a,int b){int m = a;if( a < b) m = b;return m;
}

这样,这篇博客就到此结束了,希望对小伙伴们有一定帮助,同时也欢迎小伙伴们提出自己的想法和建议。

安利一下第二篇博客记忆化递归


http://chatgpt.dhexx.cn/article/B3F6GCDp.shtml

相关文章

dp算法篇Day1

"多希望有人来陪我&#xff0c;度过末日啊~" 讲讲我为什么突然想更新这篇栏目。 想想自己也算 "系统" 接触计算机这个学科也有差不多一年了&#xff0c;回想起当初下定决心要全身心投入到这个专业或者说行业中来&#xff0c;现在到了这样的地步&#xff0c…

第十四周DP算法总结

这周自己主要再看DP算法的博客&#xff0c;感觉DP这一部分内容确实比之前的都要麻烦一些&#xff0c;最后攻克这一部分难题还是挺好的。 这周自己总结了一些题型&#xff0c;以及一些方法思路&#xff0c;最后再把动态规划和之前的分治和贪心做一下比较。下面是详细的总结。 动…

DP算法(Dynamic Programming,俗称动态规划)是最经典算法之一

DP算法&#xff08;Dynamic Programming,俗称动态规划&#xff09;是最经典算法之一.本笔记以耳熟能详的数塔问题为引子,深入讨论01背包的解决方法. 首先,如下图所示,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少&#xff1f; 这个问题,对…

DP算法:动态规划算法

步骤 &#xff08;1&#xff09;确定初始状态 &#xff08;2&#xff09;确定转移矩阵&#xff0c;得到每个阶段的状态&#xff0c;由上一阶段推到出来 &#xff08;3&#xff09;确定边界条件。 例题 蓝桥杯——印章&#xff08;python实现&#xff09; 使用dp记录状态&#x…

动态规划(DP)算法初识

先用大白话来说一下几种经典算法大概的意思&#xff1a; 贪心算法&#xff1a;我就一次机会&#xff0c;为了达到目的&#xff0c;其他的我啥也不考虑回溯算法&#xff1a;我有无数次机会&#xff0c;还能怕我有达不到目的的时候&#xff1f;动态规划算法&#xff1a;我能随意…

常用十大算法_动态规划算法(DP)

动态规划算法&#xff08;DP&#xff09; 高能预警&#xff1a;DP算法不容易理解&#xff0c;需要动脑筋查资料找例题 动态规划算法&#xff08;Dynamic Programming&#xff09;&#xff0c;是将复杂问题拆分成子问题&#xff0c;并在子问题的基础上&#xff0c;求解复杂问题…

动态规划算法(DP)

校招笔试面试前,大家一般都会先去牛客网上刷刷题,《剑指offer》,《leetcode》走起来,然后初次入手,发现很多不会,不会到什么程度呢,连个想法都没有,于是就去讨论区看答案,然后java大神,c++大神会给出花式解答,他们喜欢在答案前加一句,简单的dp算法,递归就可以解决…

【算法笔记】树形DP算法总结详解

0. 定义 树形DP&#xff0c;又称树状DP&#xff0c;即在树上进行的DP&#xff0c;是DP&#xff08;动态规划&#xff09;算法中较为复杂的一种。 1. 基础 令 f [ u ] f[u]~ f[u] 与树上顶点 u u u有关的某些数据&#xff0c;并按照拓扑序&#xff08;从叶子节点向上到根节点…

★动态规划(DP算法)详解

什么是动态规划&#xff1a;动态规划_百度百科 内容太多了不作介绍&#xff0c;重点部分是无后效性&#xff0c;重叠子问题&#xff0c;最优子结构。 问S->P1和S->P2有多少种路径数&#xff0c;毫无疑问可以先从S开始深搜两次&#xff0c;S->P1和S->P2找出所有路…

ubuntu安装qt

Ubuntu安装qt 到qt官网下载“qt-opensource-linux-x64-5.9.1.run” 分别安装g, build-essential, libglq-mesa-dev, libglu1-mesa-dev freeglut3-dev 输入指令&#xff1a;”sudo apt-get install g” -> “sudo apt-get install build-essential” -> “sudo apt-get i…

QT安装、构建套件(MSVC、MinGW)配置

QT安装、构建套件(MSVC、MinGW)配置 1. QT框架及QT Creator下载 登录QT官网-https://www.qt.io/download。 点击downloads for open source users 在页面最下方&#xff0c;点击Download the QT online Installer。 在安装网页的最下方处有一行小字 “We do recommend yo…

QT linux安装

转载地址&#xff1a;http://www.cnblogs.com/tangkaixuan/p/6504102.html 文章来自https://lug.ustc.edu.cn/sites/qtguide/ 1.4 Qt在Linux下安装 Qt在Linux系统里的安装要稍微复杂一些&#xff0c;因为Linux发行版众多&#xff0c;所以安装过程有些差异。 由于Linux系统都可…

Qt国内镜像安装

下载安装程序 https://download.qt.io/official_releases/online_installers/ 使用国内镜像打开安装程序 G:\下载\qt-unified-windows-x64-4.5.1-online.exe --mirror https://mirror.nju.edu.cn/qt清华源 https://mirrors.tuna.tsinghua.edu.cn/qt/online/qtsdkrepository/win…

Qt下载与安装

一、Qt和Qt Creator的区别 Qt是C的一个库&#xff0c;或者说是开发框架&#xff0c;里面集成了一些库函数&#xff0c;提高开发效率。 Qt Creator是一个IDE&#xff0c;就是一个平台&#xff0c;一个开发环境&#xff0c;类似的比如说VS&#xff0c;也可以进行Qt开发&#xff…

Ubuntu 安装QT

一、最近这家公司接到一个订单&#xff0c;客户使用到国产操作系统&#xff0c;意味着需要使用到 Linux 系统&#xff0c;于是乎&#xff0c;之前的东西又要捡起来&#xff0c;而且&#xff0c;平时代码主要是windows 平台&#xff0c;这次需要将代码移植到linux 平台&#xff…

QT的安装------QT

由于现在的qt都是线上下载了&#xff0c;那我们就去qt的官网下载 download.qt.io 我们选择倒数第二个------archive(档案)&#xff0c;顺便学一下英文。 然后选择online install&#xff08;在线安装&#xff09; 身为先进人&#xff0c;当然选择最新的版本&#xff08;团新版…

VS+QT安装配置

心血来潮&#xff0c;装个QT&#xff0c;遇到好多问题&#xff0c;记录一下&#xff08;铭记那些踩过的坑&#xff09; 软件版本&#xff1a;vs是2022&#xff0c;qt是6.3.1 qt下载地址&#xff1a;Download Qt | Develop Desktop & Embedded Systems | Qt 点进去往下翻&…

Windows Qt安装教程

目录 一、Qt安装包下载二、Qt安装流程 一、Qt安装包下载 Qt官网&#xff1a;https://download.qt.io/ Qt官方提供的专门的资源下载网站&#xff0c;所有的开发环境和相关工具都可以从这里下载&#xff0c;Qt 官方下载网站如下图&#xff1a; 点击进入archive目录&#xff0c;…

Qt安装教程-详细

本文主要介绍了Qt5.9.7的安装步骤。 Qt下载 Qt的下载地址: http://download.qt.io/archive/qt/ qt-opensource-windows-x86-5.9.7.exe 是一个综合的安装包(5.8之前分开下载各个编译器版本SDK)&#xff0c;下载后安装的时候可以选择安装哪个编译器对应的SDK。一般可选MinGW 或…

QT下载安装

1、下载路径 https://download.qt.io/archive/qt/5.9/5.9.9/ 文件比较大&#xff0c;建议可以Qt 镜像网站 下载 国内著名的 Qt 镜像网站&#xff0c;主要是各个高校的&#xff1a;中国科学技术大学&#xff1a;http://mirrors.ustc.edu.cn/qtproject/ 清华大学&#xff1a;htt…