CSP-J2019第二轮 解题分析

本文深入解析了四个不同的算法问题,包括数字游戏、公交换乘、纪念品买卖和加工零件。针对每个问题,分析了其核心算法,并提出了一步步的优化策略,如使用队列、双向链表和最短路算法。此外,还探讨了如何将复杂问题简化,如利用完全背包模型和迪杰斯特拉算法。最后,提到了记忆化搜索在解决这类问题中的应用。

1.数字游戏

算法分析

共8个字符,可以用循环读入,也可以用 s c a n f scanf scanf一次性读入。然后判断计数。

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
int main()
{
   
   
	char c;
	int num = 0;
	for (int i = 1; i <= 8; ++i)
	{
   
   
		cin>>c;
		if (c == '1') ++num;
	}
	cout<<num<<endl;
} 

2.公交换乘

算法分析

依次读入。判断是地铁的话,结果累加,然后将该地铁的信息放进队列中,队列用数组维护即可。判断是公交车的话,首先维护队首,让超出时间范围的地铁票出队,然后在队列中寻找票价大于当前的公交车票价的地铁票。使用过的地铁票要标记。每次是公交车的时候,最多在45个地铁中选,时间复杂度最坏情况下为 O ( 45 n ) O(45n) O(45n)

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
int q[100010], l = 1, r;
int vis[100010];
struct node
{
   
   
	int price, t;
}a[100010];
int main()
{
   
   
	int ans = 0;
	int n; scanf("%d", &n);
	int stype, sprice, st;
	for (int i = 1; i <= n; ++i)
	{
   
   
		scanf("%d%d%d", &stype, &sprice, &st);
		if (stype == 0)
		{
   
   
			ans += sprice;
			a[i].price = sprice; a[i].t = st;
			q[++r] = i;
		}else
		{
   
   
			while (l <= r && st - a[ q[l] ].t > 45) ++l;
			int ok = 0;
			for (int j = l; j <= r; ++j)
				if (a[ q[j] ].price >= sprice && vis[j] == 0)
				{
   
   
					vis[j] = 1;
					ok = 1;
					break;
				}
			if (!ok) ans += sprice;
		}
	}
	printf("%d\n", ans);
	return 0;
} 

算法拓展

用队列维护地铁票的信息,因为最优决策不具有单调性,所以还需要标记,有个更简便的办法,改用双向链表去维护地铁票的信息,可以做到 O ( 1 ) O(1) O(1)删除。数组模拟双向链表。每个地铁票只会被访问一次,整体时间复杂度 O ( n ) O(n) O(n)

3.纪念品

算法分析

每天每件纪念品可以被买和卖无限次,相当于在每天的第一时刻,把所有纪念品卖掉换成钱,然后当天后面纯是买的动作。在同一天内买卖纪念品不能赚取差价,当天买第二天卖才可能赚取差价,每个纪念品可以被无限次买,即纪念品的数量是无穷的。问题转化为:

在每一天的开始,有 m m m元钱,有 n n n个纪念品,每个纪念品有无穷多个,第 i i i个纪念品有体积为 p r i c e [ i ] price[i] price[i],即它的价格,价值为第二天的价格和当天的价格之差,可正可负。完全背包模型。

f [ i ] [ j ] : f[i][j]: f[i][j]规划到第 i i i个物品,目前手里的钱有 j j j元,将买来的纪念品第二天都卖掉,所能获得的最大收益。

f [ i ] [ j ] = m a x ( f [ i − 1 ] [ j ] , f [ i ] [   j + p [ k ] [ i ]   ] − p [ k ] [ i ] + p [ k + 1 ] [ i ] ) f[i][j] = max(f[i-1][j], f[i][\,j + p[k][i]\,] - p[k][i] + p[k+1][i]) f[i][j]=max(f[i1][j],f[i][j+p[k][i]]p[k][i]+p[k+1][i])

p [ k ] [ i ] p[k][i] p[k][i]表示第 k k k天第 i i i个纪念品的价格。

等号左侧的 j j j要小于右侧的 j + p

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值