【安徽省机器人大赛程序设计赛道(本科组)】C 联合密码、D 环保宣传 | 非专业题解

文章介绍了两道题目,一是关于联合密码的门禁系统,涉及利用两点距离公式求解最小值的问题;二是关于环保宣传,探讨如何在道路上选择装置位置以最大化影响市民,涉及市民通行数量的统计和优化策略。解题思路包括几何问题的抽象和递归函数的应用。
摘要由CSDN通过智能技术生成


题目C 联合密码

题目说明

  环保部门在城市工业区设置了环境污染物检测和预警实验室,实验室会收集工业区附近的地表及地下水系统的样本并进行检测,同时保存过往的数据用于比对。因此实验室安装了一个特殊的门禁系统,每隔一段时间就会进行调整,避免工作人员不小心对外透露相关信息。
  这款门禁系统的密码是若干个公式,每次使用2 个,然后按照要求求出指定的结果,小李今天拿到了其中 2 个,其中一个是 (x^2+a)^0.5,另一个是 ((b‐x)^2+1)^0.5。a 和 b 的信息会显示在屏幕上,今天的要求是求两个公式和的最小值。

输入说明:
  输入 ab 两个非负实数
输出说明:
  输出表达式的最小值,精确到小数点后 6 位。
输入样例:

4.000 4.000

输出样例:

5.000000

解题思路

  观察到两个公式 x 2 + a \sqrt{x^2+a} x2+a ( b − x ) 2 + 1 \sqrt{(b-x)^2 + 1} (bx)2+1 具有相似性,并且联想到平面上两点的距离公式 d = ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 d=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2} d=(x1x2)2+(y1y2)2 。将具体问题抽象成平面上的几何问题

具体解法

  将两个公式分别转化为 ( x − 0 ) 2 + ( 0 − a ) 2 \sqrt{(x-0)^2+(0-a)^2} (x0)2+(0a)2 ( x − b ) 2 + ( 0 − 1 ) 2 \sqrt{(x-b)^2+(0-1)^2} (xb)2+(01)2
  抽象出平面中的三点 P ( x , 0 ) P(x,0) P(x,0), A ( 0 , a ) A(0,\sqrt a) A(0,a ), B ( b , 1 ) B(b,1) B(b,1)。如图所示,坐标系中的折线 A P B APB APB 的长度即为所要求的两个公式和的最小值。
几何表示

  观察到 P P P点 只在 x x x轴 上移动,作点 B ′ ( b , − 1 ) B'(b,-1) B(b,1),为 B B B点 关于 x x x轴 的对称点。这样,折线 A P B APB APB 的长度即为折线 A P B ′ APB' APB 的长度。那么,两个公式和的最小值即为折线 A P B ′ APB' APB 的最小值,即 d A B = ( 0 − b ) 2 + ( a + 1 ) 2 d_{AB} = \sqrt{(0-b)^2+(\sqrt a + 1)^2} dAB=(0b)2+(a +1)2 ,对于任意的 ab 就都有唯一的 d A B d_{AB} dAB 与之对应。在代码中反映为 min = sqrt(b * b + a + 2 * sqrt(a) + 1); 一般地,sqrt() 因编译器和平台而异,使用牛顿迭代法或二分法来实现,对于本题中所要求的运算精度,该方法可实现目标。

运行结果

联合密码运行结果

CPP源码

#include <iostream>
#include <iomanip> 
#include <cmath>

using namespace std;

int main(){
	double a, b, min;
	cin >> a >> b;
	
	min = sqrt(b * b + a + 2 * sqrt(a) + 1);
	
	cout << setprecision(6) << fixed << min;
	
	return 0;
}

题目D 环保宣传

题目说明

  随着人们对环境的日益关注,H 市政府正在寻找减少碳排放和促进可持续生活的方法。然而,许多人仍然依赖汽车作为交通工具,对改变他们的习惯有抵触情绪。
  政府已经发明了一种新的宣传装置,使用积极的宣传手段来鼓励市民乘坐地铁而不是驾驶汽车。政府选择了一条道路将其作为一个宣传试验场地,以促进可持续交通,减少该市的碳足迹。这条道路可以看成一条直线,上面有 N 个和其他道路交错形成的路口,每个相邻的路口之间可以安装装置宣传到经过此段道路的市民。由于装置的价值昂贵,所以不能在每个相邻的路口之间安装装置进行宣传,所以政府决定选定 k 个相邻的路口,在路口之间安装装置进行宣传。关于每天在每对路口之间通行的市民数量的统计数据已经知晓(假设每位市民每天只通行一次,且从一个路口进,一个路口出)。现在,政府需要知道在哪些路口之间安装装置可以使得最多市民受到宣传,促进可持续交通和减少碳排放。请你帮忙计算收到宣传的最大市民数是多少。
输入说明:
  第一行包含两个整数 n , k ,表示道路经过的路口数和可以安装的装置数目。接下来 n − 1 n-1 n1 行,每行包含 n − i ( 1 ≤ i ≤ n − 1 ) n-i\left(1\le i\le n-1\right) ni(1in1) 个整数,其中第 j ( 1 ≤ j ≤ n − 1 ) j\left(1\le j\le n-1\right) j(1jn1) 个数表示第 i i i 个路口到第 i + j i+j i+j 个路口之间的每天的通行市民数量。
输出说明:
  第一行包含一个整数,表示能够收到宣传的市民最大总数。
输入样例:

4 1
5 0 6
5 3
5

输出样例:

14

样例解释:
在第三个路口和第四个路口之间安装装置,可以有 6 + 3 + 5 = 14 6+3+5=14 6+3+5=14 个市民受到宣传。
数据范围
2 ≤ n ≤ 500 2\le n\le500 2n500
1 ≤ k ≤ n − 1 1\le k\le n-1 1kn1
每对路口之间的市民数量不超过 100,可以假设每位乘客每天只有一次通行。

解题思路

  首先要意识到道路经过 n 个路口,就会构成 n-1 个路段,需要安装的装置必须是连续的路段,而且被宣传到的市民不能重复宣传。特别地,若 k = 1 k=1 k=1,每一个长度为 1 的路段所通过的市民数量 s u m i ( 1 ≤ i ≤ n − 1 ) sum_i\left(1\le i\le n-1\right) sumi(1in1) 是唯一固定的(如图所示)。一般地,对于任意给定的 k 个装置,任意长度为 k 的长路段所通过的市民数量 S U M i ( 1 ≤ i ≤ n − k ) SUM_i\left(1\le i\le n-k\right) SUMi(1ink) 也是唯一固定的。而且 S U M i SUM_i SUMi S U M i + 1 SUM_{i+1} SUMi+1 之间有一定关系,可以考虑两者之间的递归函数
人流量图示

具体解法

  构建一个二维数组 traffic[n + 1][n + 1] 用于存储每对路口之间的市民通行数量,traffic[i][j] 表示从第 i 个路口到第 j 个路口的市民通行数量。声明一个变量 SUM 用以表示 k 个相邻路段所组成的长路段市民通行总量,SUM_max 用以存储最大市民通行总量。初始时, S U M 1 SUM_1 SUM1traffic 数组头下标为1的元素之和。后续, S U M i = S U M i − 1 − ∑ x = 1 i − 1 t r a f f i c [ x ] [ i ] + ∑ x = i + 1 n t r a f f i c [ i ] [ x ] SUM_i=SUM_{i-1}-\sum_{x=1}^{i-1}{traffic[x][i]}+\sum_{x=i+1}^{n}{traffic[i][x]} SUMi=SUMi1x=1i1traffic[x][i]+x=i+1ntraffic[i][x] 。通过递归公式不断赋值给新的 SUM,不断比较更新 SUM_max

运行结果

环保宣传运行结果

cpp源码

#include <iostream>
#include <algorithm>
using namespace std;

int main() {
	//n为路口数,k为可以安装的装置数目 
    int n, k;
    cin >> n >> k;

    //二维数组traffic用于存储每对路口之间的市民通行数量
    int traffic[n + 1][n + 1]; 
    for (int i = 1; i < n; i++) {
        for (int j = i + 1; j < n + 1; j++) 
            cin >> traffic[i][j];
    }
    
    //定义SUM_max为能宣传的最大人数
	int SUM = 0, SUM_max;
	for(int x = 2; x <= n; x++)   //求SUM1
		SUM += traffic[1][x];
	SUM_max = SUM;
	//cout << "SUM = " << SUM << endl;
	//cout << "SUM_max = " << SUM_max << endl;
	
	for(int i = 2; i <= n - k; i++){
		for(int x = 1; x <= i - 1; x++)
			SUM -= traffic[x][i];
		for(int x = i + 1; x <= n; x++)
			SUM += traffic[i][x];
		SUM_max = max(SUM_max, SUM);  //不断比较赋值 
		//cout << endl << "SUM = " << SUM << endl;
		//cout << "SUM_max = " << SUM_max << endl;
	}
	
    //输出能够收到宣传的市民最大总数
    cout << SUM_max << endl;

    return 0;
}

非专业解法,仅供参考,欢迎指正!

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值