2014高教社杯全国大学生数学建模竞赛D题目

题目描述

储药柜的结构类似于书橱,通常由若干个横向隔板和竖向隔板将储药柜分割成若干个储药槽(如图1所示)。为保证药品分拣的准确率,防止发药错误,一个储药槽内只能摆放同一种药品。药品在储药槽中的排列方式如图2所示。药品从后端放入,从前端取出。一个实际储药柜中药品的摆放情况如图3所示。
为保证药品在储药槽内顺利出入,要求药盒与两侧竖向隔板之间、与上下两层横向隔板之间应留2mm的间隙,同时还要求药盒在储药槽内推送过程中不会出现并排重叠、侧翻或水平旋转。在忽略横向和竖向隔板厚度的情况下,建立数学模型,给出下面几个问题的解决方案。

  1. 药房内的盒装药品种类繁多,药盒尺寸规格差异较大,附件1中给出了一些药盒的规格。请利用附件1的数据,给出竖向隔板间距类型最少的储药柜设计方案,包括类型的数量和每种类型所对应的药盒规格。
  2. 药盒与两侧竖向隔板之间的间隙超出2mm的部分可视为宽度冗余。增加竖向隔板的间距类型数量可以有效地减少宽度冗余,但会增加储药柜的加工成本,同时降低了储药槽的适应能力。设计时希望总宽度冗余尽可能小,同时也希望间距的类型数量尽可能少。仍利用附件1的数据,给出合理的竖向隔板间距类型的数量以及每种类型对应的药品编号。
  3. 考虑补药的便利性,储药柜的宽度不超过2.5m、高度不超过2m,传送装置占用的高度为0.5m,即储药柜的最大允许有效高度为1.5m。药盒与两层横向隔板之间的间隙超出2mm的部分可视为高度冗余,平面冗余=高度冗余×宽度冗余。在问题2计算结果的基础上,确定储药柜横向隔板间距的类型数量,使得储药柜的总平面冗余量尽可能地小,且横向隔板间距的类型数量也尽可能地少。
  4. 附件2给出了每一种药品编号对应的最大日需求量。在储药槽的长度为1.5m、每天仅集中补药一次的情况下,请计算每一种药品需要的储药槽个数。为保证药房储药满足需求,根据问题3中单个储药柜的规格,计算最少需要多少个储药柜。

提出关键点

一个储药槽内只能摆放同一种药品。
要求药盒与两侧竖向隔板之间、与上下两层横向隔板之间应留2mm的间隙,同时还要求药盒在储药槽内推送过程中不会出现并排重叠、侧翻或水平旋转。在忽略横向和竖向隔板厚度的情况下,建立数学模型。

建立数学模型

模型一:储药槽和药盒关系模型

已知药盒长宽高分别是a,b,ca,b,ca,b,c毫米,设计储药槽长宽高分别是x,y,zx,y,zx,y,z毫米。

要求药盒在储药槽内推送过程中不会出现:

1.并排重叠 ,

即储药槽高度不能高于两倍的药盒高,储药槽宽度不能高于两倍的药盒宽
{z<2cy<2b\begin{cases}z\lt 2c\\y \lt 2b\end{cases}{z<2cy<2b

2.侧翻,

在这里插入图片描述

如上图,红色为药盒,分两种情况,情况一:绿色为储药槽;情况二:黑色为储药槽。

假设考虑的是不能完全侧翻情况,那么模型为:
{z<b2+c2+M(1−μ)y<b2+c2+M(1−v)μ+v≥1μ,v∈{ 0,1 }\begin{cases} z\lt \sqrt{b^2+c^2} + M(1-\mu)\\ y \lt \sqrt{b^2+c^2} + M(1-v)\\ \mu + v \ge 1\\ \mu,v \in \set{0,1} \end{cases} z<b2+c2 +M(1μ)y<b2+c2 +M(1v)μ+v1μ,v{0,1}
其中 MMM为定值,并且M≥b2+c2M \ge \sqrt{b^2+c^2}Mb2+c2

考虑实际情况,假设侧翻角度超过454545度即为侧翻
观察上图,下方绿线和红线夹角为45度时为极限角度可以得到:
y=22(a+b)y = \dfrac{\sqrt{2}}{2}(a+b)y=22 (a+b)
并且侧翻时侧面解刨图来看,长方形的一个点会和储药槽底部接触,模拟物体旋转过程发现当长方形的对角线和底部垂直时候,整个物体触顶高度达到最高值。也就是说如果储药槽设计高度低于物体的对角线长度物体将无法侧翻
可以得到模型:
{z<b2+c2+M(1−μ)y<22(a+b)+M(1−v)μ+v≥1μ,v∈{ 0,1 }\begin{cases} z\lt \sqrt{b^2+c^2} + M(1-\mu)\\ y \lt \dfrac{\sqrt{2}}{2}(a+b) + M(1-v)\\ \mu + v \ge 1\\ \mu,v \in \set{0,1} \end{cases} z<b2+c2 +M(1μ)y<22 (a+b)+M(1v)μ+v1μ,v{0,1}
其中 MMM为定值,并且M≥max⁡(b2+c2,22(a+b))M \ge \max{(\sqrt{b^2+c^2},\dfrac{\sqrt{2}}{2}(a+b))}Mmax(b2+c2 ,22 (a+b))

将45度推广为α\alphaα度(准确来讲是物体抬起的角度),模型将变为
{z<b2+c2+M(1−μ)y<bcos⁡α+ccos⁡(π2−α)+M(1−v)μ+v≥1μ,v∈{ 0,1 }\begin{cases} z\lt \sqrt{b^2+c^2} + M(1-\mu)\\ y \lt b\cos{\alpha}+c\cos{(\dfrac{\pi}{2}-\alpha)} + M(1-v)\\ \mu + v \ge 1\\ \mu,v \in \set{0,1} \end{cases} z<b2+c2 +M(1μ)y<bcosα+ccos(2πα)+M(1v)μ+v1μ,v{0,1}
其中 MMM为定值,并且M≥max⁡(b2+c2,bcos⁡α+ccos⁡(π2−α))M \ge \max{(\sqrt{b^2+c^2},b\cos{\alpha}+c\cos{(\dfrac{\pi}{2}-\alpha)})}Mmax(b2+c2 ,bcosα+ccos(2πα))

3.水平旋转 ,

实际上和侧翻的情况一类似,只是宽和高变成了长和宽
设物体水平旋转了α\alphaα度就称为水平旋转了
y<bcos⁡α+acos⁡(π2−α)y \lt b\cos{\alpha}+a\cos{(\dfrac{\pi}{2}-\alpha)}y<bcosα+acos(2πα)

要求药盒与两侧竖向隔板之间、与上下两层横向隔板之间应留2mm的间隙

{z≥c+2y≥b+2\begin{cases} z\ge c+2\\ y \ge b + 2 \end{cases}{zc+2yb+2

建立解决问题的数学模型

问题一

假设已知所有盒装药品所需的储药槽宽度xxx约束,和所有盒装药品总数NNN
ai≤xi<bi,i=1,2,3...Na_i\le x_i\lt b_i , i = 1,2,3...Naixi<bi,i=1,2,3...N

那么

解决模型一:

yjy_jyj为第jjj种竖向隔板间距类型大小
gijg_{ij}gij表示第iii种药盒可不可以放进第jjj种药槽里面

{min⁡∑j=1Mfjaigij≤yjfj<bi+M′(1−gij)∑j=1Mgij≥1fj,gij∈{ 0,1 }i=1,2,3,...N,j=1,2,3,...M\begin{cases} \min \displaystyle\sum_{j=1}^M f_j\\ a_ig_{ij} \le y_jf_j \lt b_i+M'(1-g_{ij})\\ \displaystyle\sum_{j=1}^M g_{ij} \ge 1\\ f_j , g_{ij} \in \set{0,1}\\ i = 1,2,3,...N , j = 1,2,3,...M \end{cases} minj=1Mfjaigijyjfj<bi+M(1gij)j=1Mgij1fj,gij{0,1}i=1,2,3,...N,j=1,2,3,...M
M′≥max⁡i=1NbiM'\ge \max_{i=1}^Nb_iMmaxi=1Nbi
这种模型就要先求出所有可能为竖向隔板间距类型的大小

解决模型二:

我们可以得出第iii种药盒能放进的药槽都得出来,记做dijd_{ij}dij
如果dij=1d_{ij}=1dij=1表示得出第iii种药盒能放进第jjj种药槽,反之不能
{min⁡∑j=1Mfj∑j=1Mdijfj>1fj,gij∈{ 0,1 }i=1,2,3,...N,j=1,2,3,...M\begin{cases} \min \displaystyle\sum_{j=1}^M f_j\\ \displaystyle\sum_{j=1}^M d_{ij}f_j \gt 1\\ f_j , g_{ij} \in \set{0,1}\\ i = 1,2,3,...N , j = 1,2,3,...M \end{cases} minj=1Mfjj=1Mdijfj>1fj,gij{0,1}i=1,2,3,...N,j=1,2,3,...M

解决模型三:

{aigi≤xj<bigimax⁡∑i=1Ngifj,gi∈{ 0,1 }i=1,2,3,...N,j=1,2,3,...M\begin{cases} a_ig_i \le x_j \lt b_ig_i\\ \max \displaystyle\sum_{i=1}^N g_i\\ f_j , g_i \in \set{0,1}\\ i = 1,2,3,...N , j = 1,2,3,...M \end{cases} aigixj<bigimaxi=1Ngifj,gi{0,1}i=1,2,3,...N,j=1,2,3,...M
不断增加MMM的值,直到答案∑i=1Ngi≥N\displaystyle\sum_{i=1}^N g_i \ge Ni=1NgiN,就求出其中一组解

问题二

简单来说就是要求所有 药盒与两侧竖向隔板之间的间隙超出2mm的部分 之和最小
利用上一问的模型三:
{aigi≤xj<bigimax⁡∑i=1Ngifj,gi∈{ 0,1 }i=1,2,3,...N,j=1,2,3,...M\begin{cases} a_ig_i \le x_j \lt b_ig_i\\ \max \displaystyle\sum_{i=1}^N g_i\\ f_j , g_i \in \set{0,1}\\ i = 1,2,3,...N , j = 1,2,3,...M \end{cases} aigixj<bigimaxi=1Ngifj,gi{0,1}i=1,2,3,...N,j=1,2,3,...M
其中MMM的临界值M1M_1M1在问题一已经求出
所以就可以规定M≥M1M\ge M_1MM1

同问题一的假设:
假设已知所有盒装药品所需的储药槽宽度xxx约束,和所有盒装药品总数NNN
ai≤xi<bi,i=1,2,3...Na_i\le x_i\lt b_i , i = 1,2,3...Naixi<bi,i=1,2,3...N
观察模型一:储药槽和药盒关系模型中的所有约束条件,发现aia_iai只能是药盒的宽度加两毫米,为已知量
那么药盒与两侧竖向隔板之间的间隙超出2mm的部分可以表示为:
xi−aix_i - a_ixiai
因为还要约束两侧竖向隔板之间的间隙的种类,所以
min∑j=1M∑i=1Nxj−ai,xj≥aimin \displaystyle\sum_{j=1}^M\displaystyle\sum_{i=1}^N x_j-a_i , x_j\ge a_iminj=1Mi=1Nxjai,xjai
得到

模型一:

{min∑j=1M∑i=1Nxj−ai,xj≥aiaigi≤xj<bigi∑i=1Ngi=Nfj,gi∈{ 0,1 }i=1,2,3,...N,j=1,2,3,...M\begin{cases} min \displaystyle\sum_{j=1}^M\displaystyle\sum_{i=1}^N x_j-a_i , x_j\ge a_i\\ a_ig_i \le x_j \lt b_ig_i\\ \displaystyle\sum_{i=1}^N g_i = N\\ f_j , g_i \in \set{0,1}\\ i = 1,2,3,...N , j = 1,2,3,...M \end{cases} minj=1Mi=1Nxjai,xjaiaigixj<bigii=1Ngi=Nfj,gi{0,1}i=1,2,3,...N,j=1,2,3,...M

当然这种模型求解/优化都不容易
如果换个思路,在问题一已知有多少种两侧竖向隔板之间的间隙的种类了,并且求出了对应药盒对应的两侧竖向隔板之间的间隙,那么就可以把两侧竖向隔板之间的间隙相同的都分为一组,最后形成MMM组药盒和对应的两侧竖向隔板之间的间隙

只需要每一组对应的两侧竖向隔板之间的间隙都取最小值,那么MMM组加起来也就是所有 药盒与两侧竖向隔板之间的间隙超出2mm的部分 之和最小

那么

模型二:

{aigi≤xj<bigi∑i=1Ngi=Naikj≤xj<bikjmin∑i=1Nxj−aikj,j=1,2,3,...Mfj,gi,kj∈{ 0,1 }i=1,2,3,...N,j=1,2,3,...M\begin{cases} a_ig_i \le x_j \lt b_ig_i\\ \displaystyle\sum_{i=1}^N g_i = N\\ a_ik_j \le x_j \lt b_ik_j\\ min \displaystyle\sum_{i=1}^N x_j-a_ik_j ,j = 1,2,3,...M\\ f_j , g_i , k_j\in \set{0,1}\\ i = 1,2,3,...N , j = 1,2,3,...M \end{cases} aigixj<bigii=1Ngi=Naikjxj<bikjmini=1Nxjaikj,j=1,2,3,...Mfj,gi,kj{0,1}i=1,2,3,...N,j=1,2,3,...M

发现模型二实际上就是模型一的改进,模型二利用0/1变量kjk_jkj去定位药盒所对应的两侧竖向隔板之间的间隙的同时也是在解决模型一中$ x_j\ge a_i$条件

由此就可以得到一个"通用"的解决手段:
如果出现当xi≤ajx_i\le a_jxiaj时候某个式子f(xi,aj)f(x_i,a_j)f(xi,aj)才执行/成立
f(xi,aj),xi≤ajf(x_i,a_j) , x_i\le a_jf(xi,aj),xiaj
假设为u={f(xi,aj),xi≤aj0,xi>aju = \begin{cases}f(x_i,a_j) , x_i\le a_j\\0,x_i\gt a_j\end{cases}u={f(xi,aj),xiaj0,xi>aj
这时候引入一个0/1变量kik_iki
$ \begin{cases}u =f(x_i,a_jk_i)\x_i\le a_jk_j\end{cases}$
但要注意:
1.f(xi,aj)改成f(xi,ajki)f(x_i,a_j)改成f(x_i,a_jk_i)f(xi,aj)改成f(xi,ajki)时候不能改变题目本意
2.之所以是f(xi,ajki)f(x_i,a_jk_i)f(xi,ajki)而不是f(xi,aj)kif(x_i,a_j)k_if(xi,aj)ki,是因为最好不出现决策变量和决策变量相乘
3.如果非要用f(xi,aj)kif(x_i,a_j)k_if(xi,aj)ki,需要将决策变量和决策变量相乘的模型重新转化为线性模型

问题三

储药柜的宽度不超过2.5m、高度不超过2m,传送装置占用的高度为0.5m,即储药柜的最大允许有效高度为1.5m。
假设已知所有盒装药品所需的储药槽宽度xxx约束,和所有盒装药品总数NNN
ai<xi<bi,i=1,2,3...Na_i\lt x_i\lt b_i , i = 1,2,3...Nai<xi<bi,i=1,2,3...N
假设已知所有盒装药品所需的储药槽高度度yyy约束,和所有盒装药品总数NNN
ci<yi<di,i=1,2,3...Nc_i\lt y_i\lt d_i , i = 1,2,3...Nci<yi<di,i=1,2,3...N
则:
储药柜的宽度不超过2.5m
∑i=1Nxi≤2500\displaystyle\sum_{i=1}^N x_i \le 2500i=1Nxi2500
储药柜的最大允许有效高度为1.5m
∑i=1Nyi≤1500\displaystyle\sum_{i=1}^N y_i \le 1500i=1Nyi1500

在问题二中宽度冗余为∑i=1Nxj−aikj\displaystyle\sum_{i=1}^N x_j-a_ik_ji=1Nxjaikj
同理我们也可以得到高度冗余为∑i=1Nyj−cilj\displaystyle\sum_{i=1}^N y_j-c_il_ji=1Nyjcilj
平面冗余=高度冗余×宽度冗余
即平面冗余为(∑i=1Nxj−aikj)(∑i=1Nyj−cilj)(\displaystyle\sum_{i=1}^N x_j-a_ik_j)(\displaystyle\sum_{i=1}^N y_j-c_il_j)(i=1Nxjaikj)(i=1Nyjcilj)

要使横向隔板间距的类型数量也尽可能地少。我们可以利用问题一中的模型求出横向隔板间距的类型数量临界值M2M_2M2

{aigi≤xj<bigi∑i=1Ngi=Ncioi≤yk<dioi∑i=1Noi=Naihj≤xj<bihjailk≤yk<bilkmin(∑i=1Nxj−aihj)(∑i=1Nyk−cilk),j=1,2,3,...Mfj,gi,hj,oi,lk∈{ 0,1 }i=1,2,3,...N,j=1,2,3,...M,k=1,2,3,...K\begin{cases} a_ig_i \le x_j \lt b_ig_i\\ \displaystyle\sum_{i=1}^N g_i = N\\ c_io_i\le y_k\lt d_io_i\\ \displaystyle\sum_{i=1}^N o_i = N\\ a_ih_j \le x_j \lt b_ih_j\\ a_il_k \le y_k \lt b_il_k\\ min (\displaystyle\sum_{i=1}^N x_j-a_ih_j)(\displaystyle\sum_{i=1}^N y_k-c_il_k) ,j = 1,2,3,...M\\ f_j , g_i , h_j , o_i ,l_k\in \set{0,1}\\ i = 1,2,3,...N , j = 1,2,3,...M ,k = 1,2,3,...K \end{cases} aigixj<bigii=1Ngi=Ncioiyk<dioii=1Noi=Naihjxj<bihjailkyk<bilkmin(i=1Nxjaihj)(i=1Nykcilk),j=1,2,3,...Mfj,gi,hj,oi,lk{0,1}i=1,2,3,...N,j=1,2,3,...M,k=1,2,3,...K

问题四

已知第iii种药品编号对应的最大日需求量为eie_iei和该药盒长度为ziz_izi毫米
在储药槽的长度为1.5m、每天仅集中补药一次的情况下,计算每一种药品需要的储药槽个数xix_ixi.
2∗1500ei∗zi≤xi\dfrac{2*1500}{e_i*z_i}\le x_ieizi21500xi
这样就得出了所有药品对应所需储药槽个数xix_ixi
在问题三中得出了一个药柜中所有横向(竖向)隔板间距的类型大小以及数量
同问题二从模型一到模型二的分组思路,每个药品其实对应一个组别
可以得出第iii种药品对应的组号mim_imi,并且也知道组号mim_imi对应的储药槽的个数σmi\sigma_{m_i}σmi

假设有MMM组,xjix_{ji}xji表示第jjj组第iii种药品对应所需储药槽个数,σj\sigma_jσj表示一个药柜种组号jjj对应的储药槽的个数。
得到问题模型:
min(maxj=1M∑i=1Njxjiσj)min(max_{j=1}^M \dfrac{\displaystyle\sum_{i=1}^{N_j} x_{ji}}{\sigma_j})min(maxj=1Mσji=1Njxji)

解决问题

问题一

模型一

在此之前已经初始化药盒长宽高分别放进数组length,weight,height中
处理一下数据,得到模型一的aia_iaibib_ibi,并且得到yjy_jyj的所以可能取值
C++

void solve(){
    outFile.open("data.xlsx");
    if (!outFile.is_open()) {
        std::cerr << "无法打开文件" << std::endl;
        return ;
    }
    set<double>y;
    double a[N],b[N];
    for(int i=1;i<=1919;i++){
        a[i] = 2+weight[i];
        y.insert(a[i]);
        b[i] = min({2.0*weight[i],sqrt(weight[i]*weight[i] + height[i]*height[i]), sqrt(weight[i]*weight[i] + length[i]*length[i])});
        y.insert(b[i]);
    }
    for(int i=1;i<=1919;i++){
        outFile << a[i] << '\t';
    }
    outFile << '\n';
    for(int i=1;i<=1919;i++){
        outFile << b[i] << '\t';
    }
    outFile << '\n';
    for(auto x:y){
        outFile << x << '\t';
    }
}

这样我们就完成了上面讲的先求出所有可能为竖向隔板间距类型的大小

线性化:

void solve(){
    outFile.open("data.xlsx");
    if (!outFile.is_open()) {
        std::cerr << "无法打开文件" << std::endl;
        return ;
    }
    set<double>y;
    double a[N],b[N];
    for(int i=1;i<=1919;i++){
        a[i] = 2+weight[i];
        y.insert(a[i]);
        b[i] = min({2.0*weight[i],sqrt(weight[i]*weight[i] + height[i]*height[i]), sqrt(weight[i]*weight[i] + length[i]*length[i])});
        if((long long)b[i] == b[i])b[i]--;
        b[i] = (int)b[i];
    }
    for(int i=1;i<=1919;i++){
        outFile << a[i] << '\t';
    }
    outFile << '\n';
    for(int i=1;i<=1919;i++){
        outFile << b[i] << '\t';
    }
    outFile << '\n';
    cout << (int)y.size();
    for(auto x:y){
        outFile << x << '\t';
    }
}

解决模型一:

sets:
 aa/1..1919/:a,b;
 bb/1..47/:f,y;
 cc(aa,bb):g;
endsets
data:
 a=@ole("D:\homewrok\建模\储药柜的设计问题\data.xls",A1:BUU1);
 b=@ole("D:\homewrok\建模\储药柜的设计问题\data.xls",A2:BUU2);
 y=@ole("D:\homewrok\建模\储药柜的设计问题\data.xls",A3:AU3);
enddata
min=@sum(bb(j):f(j));
@for(aa(i):@for(bb(j):a(i)*g(i,j)<y(j)*f(j)));
@for(aa(i):@for(bb(j):b(i)+58*(1-g(i,j))>y(j)*f(j)));
@for(aa(i):@sum(bb(j):g(i,j))>1);
@for(cc(i,j):@bin(g(i,j)));
@for(bb(j):@bin(f(j)));

解得

  Global optimal solution found.
  Objective value:                              4.000000
  Objective bound:                              4.000000
  Infeasibilities:                              0.000000
  Extended solver steps:                               0
  Total solver iterations:                            13


                       Variable           Value        Reduced Cost
                          F( 7)        1.000000            1.000000
                         F( 22)        1.000000            1.000000
                         F( 33)        1.000000            1.000000
                         F( 47)        1.000000            1.000000

对应类型长度为:
18,33,44,58

模型二求解

C++预处理数据

void solve(){
    outFile.open("data2.xlsx");
    if (!outFile.is_open()) {
        std::cerr << "无法打开文件" << std::endl;
        return ;
    }
    double a[N],b[N];
    for(int i=1;i<=1919;i++){
        a[i] = 2+weight[i];
        b[i] = min({2.0*weight[i],sqrt(weight[i]*weight[i] + height[i]*height[i]), sqrt(weight[i]*weight[i] + length[i]*length[i])});
        b[i] = (int)(b[i]+0.5);
    }
    for(int i=1;i<=1919;i++){
        for(int j=12;j<=58;j++){
            int flag = a[i]<j&&j<b[i];
            outFile << flag << '\t';
        }
        outFile << '\n';
    }
}
sets:
 aa/1..1919/:;
 bb/1..47/:f;
 cc(aa,bb):d;
endsets
data:
 d = @ole("D:\homewrok\建模\储药柜的设计问题\data2.xls",A1:AU1919);
enddata
min=@sum(bb(j):f(j));
@for(aa(i):@sum(bb(j):d(i,j)*f(j))>1);
@for(bb(j):@bin(f(j)));

得到

  Global optimal solution found.
  Objective value:                              4.000000
  Objective bound:                              4.000000
  Infeasibilities:                              0.000000
  Extended solver steps:                               0
  Total solver iterations:                            58


                       Variable           Value        Reduced Cost
                          F( 8)        1.000000            1.000000
                         F( 23)        1.000000            1.000000
                         F( 33)        1.000000            1.000000
                         F( 47)        1.000000            1.000000

对应类型长度为:
19,34,44,58

纯编程求解:

问题一转换:给出1919个范围[ai,bi][a_i,b_i][ai,bi],问最少取多少个点使得每个范围内至少有一个点

vector<pair<int,int>>v(1919);
void solve(){
    double a[N],b[N];
    for(int i=1;i<=1919;i++){
        a[i] = 2+weight[i];
        b[i] = min({2.0*weight[i],sqrt(weight[i]*weight[i] + height[i]*height[i]), sqrt(weight[i]*weight[i] + length[i]*length[i])});
        if((long long)b[i] == b[i])b[i]--;
        b[i] = (int)b[i];
        v[i-1].first = a[i]  , v[i-1].second=b[i];
    }
}
void solve2(){//贪心 每次未放入取上限最小的上限
    sort(v.begin(),v.end(),[&](pair<int,int> x, pair<int,int> y){
       if(x.first == y.first)return x.second < y.second;
       return x.first < y.first;
    });
    int cnt = 0 , start=0 , end;
    vector<pair<int,int>>ans;
    while(cnt < 1919){
        double x = v[start].second;
        cnt++;
        bool flag = false;
        for(int i=start;i<v.size();i++){
            if(v[i].first>x){
                end = i-1;
                flag = true;
                break;
            }
        }
        if(flag)
            ans.push_back(make_pair(v[end].first,x));
        else{
            ans.push_back(make_pair(v[v.size()-1].first,x));
            break;
        }
        start = end+1;
    }
    cout << cnt << '\n';//答案 4 个
    for(auto x:ans){
        cout << x.first << ',' << x.second << '\n';
    }
}

问题二转换:给出1919个范围[ai,bi][a_i,b_i][ai,bi],给出最少取多少个点使得每个范围内至少有一个点,求全部可能取值
注:不知道最小值为4,当新题做

vector<int>ans2;
int now_ans = 47;
int k=0;//不同取值种类数
int main() {
    solve();
    sort(v.begin(),v.end(),[&](pair<int,int> x, pair<int,int> y){
        if(x.first == y.first)return x.second < y.second;
        return x.first < y.first;
    });
    solve2_f(0,1);
    cout << k;
    return 0;
}
void solve2_f(int start ,  int cnt){
    if(cnt > now_ans)return ;
    for(int i = v[start].second;i>=v[start].first;i--){
        bool flag = false;
        for(int j=start;j<v.size();j++){
            if(v[j].first>i){
                flag = true;
                ans2.push_back(i);
                solve2_f(j,cnt+1);
                ans2.pop_back();
                break;
            }
        }
        if(!flag){
            ans2.push_back(i);
            for(auto x:ans2)cout << x << ' ';
            cout << '\n';
            ans2.pop_back();
            now_ans = min(now_ans,cnt);
        }
    }
}

问题二

纯编程求解:

在上一个问题基础上加个冗余计算即可

void solve2_f(int start ,  int cnt ,int rong){
    if(cnt > now_ans)return ;
    for(int i = v[start].second;i>=v[start].first;i--){
        bool flag = false;
        int sum = 0;
        for(int j=start;j<v.size();j++){
            if(v[j].first>i){
                flag = true;
                ans2.push_back(i);
                solve2_f(j,cnt+1,rong + sum);
                ans2.pop_back();
                break;
            }
            sum += i-v[j].first;
        }
        if(!flag){
            k++;
            ans2.push_back(i);
            for(auto x:ans2)cout << x << ' ';
            cout << "rong:" << rong;
            cout << '\n';
            ans2.pop_back();
            now_ans = min(now_ans,cnt);
        }
    }
}

求解得到最小的有

19 33 44 60 rong:10875
19 33 44 59 rong:10875
19 33 44 58 rong:10875

答案为19,33,44,58
因为最后一个取值没有计算冗余度,明显取58时候冗余度是最少的

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐