NIOP 2015 推销员

文章讲述了通过优化算法来解决疲劳计算问题,首先给出了原始代码,由于时间复杂度问题导致效率不高,然后提出对疲劳值进行降序排序,从而减少计算次数,达到提高效率的目的。这种方法通过选取最大值来确定距离,避免了多次选择导致的无效计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先看数据,O(n)/O(nlogn)

很容易可以想出第k次的疲劳是在(k-1)次的基础上选择一个max(在已知最大点左边+此点的疲劳,(在已知最大点右边-已知最大点)*2+此点的疲劳)

于是很容易得出代码

#include<cmath>
#include<cstring>
#include<string>
#include<iostream>
#include<cstdio>
#include<vector>
#include<ctime>
#include<unordered_map>
#include<map>
#include<cstdlib>
#include<iomanip>
#include<queue>
#include<set>
#include<stack>
#include<algorithm>
#include<fstream>
using namespace std;
int s[1000000],tr[1000000],d[1000000],vis[1000000];
int main()
{
//	freopen("salesman.in","r",stdin);
//	freopen("salesman.out","w",stdout);
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>s[i];
	int maxx=0,maxxp=0;
	for(int i=1;i<=n;i++)
	{
		cin>>tr[i];
		int u=s[i]*2+tr[i];
		if(u>maxx)
		{
			maxx=u;
			maxxp=i;	
		}
	}
	vis[maxxp]=1;
	cout<<maxx<<endl;
	d[1]=maxx;
	for(int i=2;i<=n;i++)
	{
		int v=0;
		for(int j=1;j<=n;j++)
		{
			if(vis[j])
				continue;
			if(j<maxxp)
				if(d[i-1]+tr[j]>d[i])
				{
					d[i]=d[i-1]+tr[j];
					v=j;
				}	
			if(j>maxxp)
				if(d[i-1]+(j-maxxp)*2+tr[j]>d[i])
				{
					d[i]=d[i-1]+(j-maxxp)*2+tr[j];
					v=j;
				}
		}	
		maxxp=max(maxxp,v);	
		vis[v]=1;
	}
	for(int i=2;i<=n;i++)
		cout<<d[i]<<endl;
	return 0;
}

 但这个代码时间复杂度超了

于是我们便把疲劳从大到小排序,再确定距离

每次确定距离时,要在前i个点与后(n-i)个点中确定一个最大值,

即在前i个点中,去点第i个点,再从(i+1)个点到n中选出一个距离+该点疲劳值最大值即可

为什么不选两个点及以上呢?

如果在后面选了一个点,那此时的距离已经达到最大,如果再选一个点的话只会减小疲劳值(已经排好序了),所以只选一个点就够

#include<cmath>
#include<cstring>
#include<string>
#include<iostream>
#include<cstdio>
#include<vector>
#include<ctime>
#include<unordered_map>
#include<map>
#include<cstdlib>
#include<iomanip>
#include<queue>
#include<set>
#include<stack>
#include<algorithm>
#include<fstream>
using namespace std;
struct node
{
	int s,tr;
}e[10000000];
int qian[10000000],hou[10000000],s[10000000];
int cmp(node a,node b)
{
	return a.tr>b.tr;
}
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>e[i].s;
	for(int i=1;i<=n;i++)
		cin>>e[i].tr;
	sort(e+1,e+n+1,cmp);
	for(int i=1;i<=n;i++)
		s[i]=s[i-1]+e[i].tr;
	for(int i=1;i<=n;i++)
		qian[i]=max(e[i].s*2,qian[i-1]);
	for(int i=n;i>=1;i--)
		hou[i]=max(hou[i+1],e[i].s*2+e[i].tr);
	for(int i=1;i<=n;i++)
		cout<<max(qian[i]+s[i],hou[i]+s[i-1])<<endl;
	return 0;
}

### NOIP2008 提高组 概述 NOIP2008(全国青少年信息学奥林匹克联赛)提高组的比赛吸引了众多选手参与。该赛事旨在考察参赛者在算法设计、编程实现等方面的能力。 ### 题目概述 比赛共设有四道题目,涵盖了不同的知识点和技术要点: 1. **传纸条** 这是一道经典的动态规划问题,要求计算从矩阵一角到另一角传递消息的最大价值路径[^3]。 2. **双栈排序** 此题涉及数据结构的应用,特别是栈的操作及其组合使用来完成特定序列的排序任务[^4]。 3. **笨小猴** 主要测试字符串处理能力以及简单的贪心策略应用,在给定条件下寻找最优解方案[^5]。 4. **火柴棒等式** 属于数论范畴,通过调整算术表达式的构成部分使得最终结果满足一定条件下的最大可能性[^6]。 ### 解题思路分析 针对上述各题目的解决方案通常会经历如下思考过程: 对于《传纸条》这类最优化求解类问题,可以采用二维数组记录状态转移方程的方式来进行高效解答;而对于像《双栈排序》这样的结构性难题,则需充分理解并灵活运用所掌握的数据结构特性,比如利用两个栈模拟队列操作从而达到预期效果;至于《笨小猴》,则更多依赖于对输入模式的理解与快速匹配技巧;最后,《火柴棒等式》考验的是考生们如何巧妙转换视角看待传统数学运算规则,并据此构建合理的枚举框架以穷尽所有可行选项。 ```cpp // 示例代码片段展示一种可能用于解决“传纸条”的方法 #include <iostream> using namespace std; const int MAXN = 50 + 5; int dp[MAXN][MAXN], a[MAXN][MAXN]; int main() { // 初始化及读入省略... for (int i = n; i >= 1; --i) { for (int j = m; j >= 1; --j) { dp[i][j] = max(dp[i+1][j],dp[i][j+1]) + a[i][j]; } } cout << "The maximum value is:" << endl; cout << dp[1][1]<<endl; return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值