暑假练习题22.06.20

 #题目

## 日期排序

## 烦恼的高考志愿

## 开餐馆

第一题   考察纯数字结构体排序

有一些日期,日期格式为 “MM/DD/YYYY”。

编程将其按日期大小排列。

输入格式

输入第一行一个整 n(1≤n≤1000),表示日期的个数。

接下来 n 行按照题目描述的格式输入 n 个日期。

输出格式

输出从早到晚排序后的日期,一个日期占一行,日期输出的格式和输入一样。

Sample 1

输入
8
01/26/1998
09/26/1927
01/05/1927
04/16/2024
08/08/1993
01/01/2019
06/22/1973
07/16/2030
输出
01/05/1927
09/26/1927
06/22/1973
08/08/1993
01/26/1998
01/01/2019
04/16/2024
07/16/2030
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 1010;
int n;
char a;
struct Node
{
	int x, y, z;//x代表天,y代表月,z代表年;
}node[N];
bool cmp(Node a, Node b)
{
	if (a.z != b.z)
	{
		return a.z < b.z;
	}
	else
	{
		if (a.y != b.y)
		{
			return a.y < b.y;
		}
		else
		{
			return a.x < b.x;
		}
	}
}
int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> node[i].y >> a >> node[i].x >> a >> node[i].z;
	}


	sort(node, node + n, cmp);


	for (int i = 0; i < n; i++)
	{
		if (node[i].y / 10 != 0)
		{
			cout << node[i].y << "/";
		}
		else
		{
			cout << "0" << node[i].y << "/";
		}
		if (node[i].x / 10 != 0)
		{
			cout << node[i].x << "/";
		}
		else
		{
			cout << "0" << node[i].x << "/";
		}
		cout << node[i].z << endl;
	}
}

 

第二题 烦恼的高考志愿  考察二分查找

计算机竞赛小组的蒜头君终于结束了万恶的高考,然而作为班长的他还不能闲下来,
班主任给了他一个艰巨的任务:帮同学找出最合理的大学填报方案。可是蒜头君太忙了,
身后还有一群小姑娘等着和他约会,于是他想到了同为计算机竞赛小组的你,请你帮他
完成这个艰巨的任务。

根据 n 位学生的估分情况,分别给每位学生推荐一所学校,要求学校的预计分数线
和学生的估分相差最小(可高可低,毕竟是估分嘛),这个最小值为不满意度。求所
有学生不满意度和的最小值。

输入格式
读入数据有三行,第一行读入两个整数 m,n(1<= m,n <= 10^5),m 表示学校数,n 表示学生数。

第二行共有 m 个正整数,表示 m 个学校的预计录取分数,不超过 10^6。

第三行有 n 个正整数,表示 n 个学生的估分成绩,不超过 10^6。

输出格式
输出数据有一行,为最小的不满度之和。

输出时每行末尾的多余空格,不影响答案正确性

样例输入 
4 3
513 598 567 689
500 600 550
样例输出 
32

 分析看到这道题先想到暴力写,但是会超内存,然后我想到了二分,但二分写一直过不了,就请教了大佬,原来我只是考虑了二分的下界限,没考虑上界限 ;然后还学会了用二分函数解这道题。下面上代码。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 100100;
int a[N];
int n, m;
int t;
int findFirst(int x)
{
	int l = 0, r = n;
	while (l < r)
	{
		int mid = (l + r) / 2;
		if (a[mid] >= x)r = mid;
		else l = mid + 1;
	}
	return l;
}
int main()
{
	cin >> n >> m;
	for (int i = 0; i < n; i++)cin >> a[i];

	sort(a, a + n);

	long long ans = 0;//注意要用long long 
	while (m--)
	{
		cin >> t;

		int mid = findFirst(t);
		int mi= 0x3f3f3f3f;

		if (mid < n) mi = min(mi, abs(a[mid] - t));//考虑上边界
		//当t<=a[n-1]时,mid<n;
		//当a[n-1]<t时,mid=n;//执行下面的if语句

		if(mid - 1 >= 0) mi = min(mi, abs(t - a[mid - 1]));//考虑下边界
		//当a[0]<t时,mid>0;
		//当t<=a[0]时,mid=0;//执行上面的if语句

		//当a[0]<t<=a[n-1]时,由上面两个if语句寻找mid两边的最小值
		ans += mi;
	}
	cout << ans << endl;
	return 0;
}

 

第三题 开餐馆,考察动态规划

蒜头君想开家餐馆. 现在共有 n个地点可供选择。蒜头君打算从中选择合适的位置开设一些餐馆。这 nn 个地点排列在同一条直线上。我们用一个整数序列 M1, M2, ... Mn​ 来表示他们的相对位置。由于地段关系, 开餐馆的利润会有所不同。我们用 pi​ 表示在 mi​ 处开餐馆的利润。

为了避免自己的餐馆的内部竞争,餐馆之间的距离必须大于 k。

请你帮助蒜头君选择一个总利润最大的方案。

输入格式

标准的输入包含若干组测试数据。

输入第一行是整数 T (1≤T≤1000),表明有 T组测试数据。紧接着有 T 组连续的测试。每组测试数据有 3 行;

第 1 行:地点总数 n(n<100), 距离限制 k (k>0 && k < 1000);

第 2 行: nn 个地点的位置 M1 , M2, ... Mn (1000000>mi​>0 且为整数, 升序排列);

第 33 行: nn 个地点的餐馆利润 p1 , p2, ... pn ​(1000>pi​>0 且为整数)。

输出格式

对于每组测试数据可能的最大利润。

分析

写动态规划,我们要思考的问题就是是否在第i个位置开餐馆;
那么什么情况下要开?什么情况下不开呢?
首先,两个餐馆之间的距离要大于K才能保证没有相互竞争,那么就是有m[i]-m[j]>k,这个时候可以考虑在第i处开餐馆,建设用f[i]来表是在前i个位置开餐馆能够得到的最大利益,那么有如下的状态转移方程:

f[i]=max(f[i-1],f[j]+p[i])
f[i-1]就是不在第i处开餐馆的情况下,最大利润就等于f[i-1];
f[j]+p[i]表示在第i处开餐馆,j是满足与i相隔具体大于k的位置,
f[j]是在前j处开餐馆的最大利润,加上p[i]就是在前i处开餐馆
的最大利润。

 循环

for(int i=2;i<=n;i++)
		for(int j=0;j<i;j++)
		{
			if((m[i]-m[j]>k) || (!j))
			    f[i]=max(f[i-1],f[j]+p[i]);
		}

具体实现过程,用样例带入体验一下

 

 

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int m[1000], p[1000], f[1000], t[1000], T, n, k;
int main()
{
	cin >> T;
	for (int x = 1; x <= T; x++)
	{
		cin >> n >> k;
		for (int i = 1; i <= n; i++) cin >> m[i];
		for (int i = 1; i <= n; i++) cin >> p[i];
		memset(f, 0, sizeof(f));
		f[1] = p[1];
		for (int i = 2; i <= n; i++)
		{
			for (int j = 0; j < i; j++)
			{
				if ((m[i] - m[j] > k) || (!j))
					f[i] = max(f[i - 1], f[j] + p[i]);
			}
		}
		t[x] = f[n];
	}
	for (int i = 1; i <= T; i++) cout << t[i] << endl;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值