2018年清华大学软件学院夏令营机试题解

原题博客:

https://blog.csdn.net/wangkingkingking/article/details/80666385

第二题我觉得他的做法会TLE。

5e9肯定只能n啊

但是我这个人代码老是写错,所以希望大家指正一下。

前提:a一定要小于5e9。我觉得作为一道正常的题目,a到1e7就够了吧,硬要卡MLE就是狗了

思路:

我的想法是,因为凸函数的任何极小值也是最小值。严格凸函数最多有一个最小值。所以我们可以从差分(相当于求导)的思路来做,首先讲f(i)作差分,存进一个数组,然后每行输入一个a,b。动动脑子就知道b肯定是没有用的,所以相当于所有的差分数组加a求最接近0的值就是f(i)的最值。但是如果根据差分的递减性质进行二分查找,这就是一个没有灵魂的算法,因为复杂度还是log没有根本的变化。

因此其实差分后我们还要做一个预处理,将差分数组进行四舍五入,然后存入一个新的数组。这里就是我觉得题目应该不太对的地方,因为a应该会有一个取值范围的,这样我们记录a取值范围内的四舍五入结果到一个数组里面。(这里会有负数,所以可能要做一个简单的数组变化,就是将1e7当作0)然后对差分数组进行遍历四舍五入,如果在-1e7-1e7之内,就将差分的下标存在具体数据里面。

然后再考虑一下重复的情况。重复的情况就是假设有一块四舍五入全部都是一个数。找最接近的那一个。考虑到上凸函数的性质,只要找到最接近整数的那一个数就行了。因此,再设置一个double 型数组存未四舍五入的值。如果下表数组为-1(初始化,表示没有存过),则直接存储double型和int型。否则,比较double的结果,如果更加接近,替换。否则,过掉。

这样的好处是,只要获得了一个a,就已经知道了位置(int型数组的-a)。直接输出哪个位置的新函数结果即可。注意考虑最顶端的两个到底谁大谁小,因此比较一下即可。


代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
int n,m;
double f[5000000005];
double cha[5000000005];
double zhi[5000000005*2];
int shu[5000000005*2];
int bian(int a)
{
	return a+5000000000;
}
int main()
{
	while (~scanf("%d%d",&n,&m))
	{
		for (int i=0;i<m;i++)
		{
			scanf("%lf",&f[i]);
		}
		//用n的复杂度作差分 
		for (int i=0;i<m-1;i++)		
		{
			cha[i]=f[i+1]-f[i];
		}
		//用n的复杂度初始化 
		memset(shu,-1,sizeof(shu));
		//用n的复杂度预处理,确保每一个shu数组里存放着差值最接近i的下标 
		for (int i=0;i<m-1;i++)
		{			
			int xiabiao=int(cha[i]+0.5)+5000000000;
			if (xiabiao<0||xiabiao>5000000000*2) continue;//超出范围直接取消,因为没用 
			if (shu[xiabiao]==-1)
			{
				shu[xiabiao]=i;
				zhi[xiabiao]=cha[i];
				continue;
			}
			if (shu[xiabiao]!=-1)
			{
				if (fabs(cha[i]-i)<fabs(zhi[xiabiao]-i))
				{
					shu[xiabiao]=i;
					zhi[xiabiao]=cha[i];
					continue;
				}
			}
		}
		int a,b;
		for (int i=0;i<m;i++)
		{
			scanf("%d%d",&a,&b);
			int xiabiao=shu[bian(-a)];
			double shu1=f[xiabiao]+a*xiabiao+b;
			xiabiao++; 
			double shu2=f[xiabiao]+a*xiabiao+b;
			printf("%lf\n",max(shu1,shu2));
		} 
	}
	return 0;
} 

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
针对2018高教社杯全国大学生数学建模竞赛D题,我们可以采取以下步骤进行题: 1. 确定问题:该题的问题是要求我们设计一种算法,能够在给定的网络拓扑结构下,计算出任意两个节点之间的最短路径长度。 2. 分析问题:该题的难点在于如何处理网络中存在的环路和负权边,这些都会影响到最短路径的计算。因此,我们需要选择一种合适的算法来决这些问题。常用的算法包括Dijkstra算法、Bellman-Ford算法、Floyd算法等。 3. 确定算法:鉴于本题的网络规模较小,我们可以考虑使用Floyd算法来决。Floyd算法适用于任意两点之间的最短路径计算,可以同时处理有向图和无向图、带权图和不带权图等多种情况,同时也能够处理负权边和环路。 4. 实现算法:实现Floyd算法的关键是构造一个邻接矩阵,表示网络中各个节点之间的距离。具体实现过程可以参考以下步骤: a. 初始化邻接矩阵:将所有节点之间的距离初始化为正无穷大,将每个节点到自己的距离初始化为0。 b. 利用邻接矩阵进行计算:对于每一对节点i和j,遍历所有节点k,比较节点i到k再到节点j的距离和节点i到节点j的距离,取最小值更新邻接矩阵中的距离值。 c. 输出结果:遍历邻接矩阵,输出任意两个节点之间的最短路径长度。 5. 检验算法:为了验证算法的正确性,可以选择一些节点进行测试,比较计算结果与实际情况是否一致。 综上所述,通过采用Floyd算法,我们可以有效地2018高教社杯全国大学生数学建模竞赛D题中的最短路径问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值