2019-2020学年上学期《算法设计与分析》期中小测

A 前夜

题目描述

Description
《前夜》讲述了开国大典自动升旗装置设计师林致远,在开国大典前夜,仍然在测试升旗装置。目的是让国旗升起的速度确保和国歌一致。国旗一定要在46秒,不多不少的到达旗顶。凌晨时分,林致远发现旗杆顶部的阻断装置坏掉,而又收集不到适合的材料炼钢,坐在房间里颓废消沉。无数的人提着灯笼赶来大典筹备处,把因为停电而灰暗的庭院照得异常明亮,带来的还有人们的支持和希望。面对群众送来的众多材料,林致远需要尽可能快的确定是否有他需要的某种硬度的材料,以便制作阻断装置。
Input
第一行,一个数字n代表有n种材料的硬度,0<n≤110000
第二行,n个数字,以空格分隔,已经按照硬度从小到大排好顺序
接下来若干行,每行一个数字,表示查询的材料的硬度。如果数字为0,表示查询结束
Output
对于每个查询,输出一行。如果找到了,输出yes。如果没有找到,输出no。
Sample Input 1

5
2 3 5 7 9
1 
2 
5
10
0

Sample Output 1

no
yes
yes
no

Hint 使用while循环读入多次查询 int q;
cin >> q;
while ( q > 0 )
{ … cin>> q }

思路

一个简单的使用二分查找的题目

参考代码

#include <iostream>
using namespace std;
bool bi_search(int a[],int n,int q)
{
	int l=0,r=n-1;
	int mid=(l+r)/2;
	while(l<=r)
	{
		mid=(l+r)/2;
		if(q==a[mid]) return true;
		if(q>a[mid]) l=mid+1;
		else r=mid-1;
	}
	return false;
}
int main()
{
	int n;
	cin>>n;
	int a[n];
	for(int i=0;i<n;i++) cin>>a[i];
	int q;
	cin>>q;
	while(q>0)
	{
		if(bi_search(a,n,q)) cout<<"yes"<<endl;
		else cout<<"no"<<endl;
		cin>>q; 
	}
	return 0;
}

拓展

二分查找函数的实现:
方法一:运用递归

int biSearch(int x, int a[],  int left, int right) {
  if (left > right) //当数组中没有元素时
      return -1;
  count++;
  int middle = (left + right) / 2;
  if (a[middle] == x) //如果找到,直接返回位置
     return middle;
  else if (a[middle] > x) //如果中间的数字大于x,在数组左半部分递归查找
     return biSearch(x, a, left, middle - 1);
  else //否则在数组右半部分递归查找
    return biSearch(x, a, middle + 1, right);
}

方法二:非递归

bool bi_search(int a[],int n,int q)
{
	int l=0,r=n-1;
	int mid=(l+r)/2;
	while(l<=r)
	{
		mid=(l+r)/2;
		if(q==a[mid]) return true;
		if(q>a[mid]) l=mid+1;
		else r=mid-1;
	}
	return false;
}

方法三:

stl中的binary_search()函数实现二分查找
binary_search(arr[],arr[]+size , indx)
详细介绍参考:
stl中binary_search()函数等介绍

B 夺冠

题目描述

Description
《夺冠》以1984年8月8日中国女排奥运会夺冠、首获世界大赛三连冠的历史瞬间为背景,将故事视线拉回80年代的上海,以一个小男孩的视角和弄堂邻里的背景回顾了35年前那个举国沸腾的夺冠时刻。男孩冬冬的同学小美要去国外了,他想给她送一张给她画的小画,小美来找他了,可楼下一巷子的人等着他弄屋顶的天线,看女排夺冠。冬冬他爸骑车回来了。他终于大哭。他爸问他为什么哭。他说:“爸,我们家的电视天线太烂了“。他爸说:“那我把他修好,男子汉别哭了”。冬冬继续哭,说“女排夺冠我太激动了”。东东的爸爸决定修理家里的天线,从一堆天线中找一根最合适的换掉旧的天线,要求刚好不长不短。要求使用平均时间复杂度为O(logn)的算法实现。
Input
第一行一个数字n,表示有n个天线。0<n<70000000
接下来一行,有n个整数,以空格分隔,表示n个天线的长度
Output
长度刚好是最中间的天线的长度。如果是偶数,输出中间较短的
Sample Input 1

5
6 2 1 9 7

Sample Output 1

6

Sample Input 2

6
2 5 3 1 4 6

Sample Output 2

3

基本思路

运用快速排序后选出位于中间的数

参考代码一(快排原理实现)

#include <bits/stdc++.h>
using namespace std;
int a[70000005];
int partition(int a[],int l,int r)
{
	int i=l,j=r+1;
	int x=a[l];
	while(true)
	{
		while(a[++i]<x&&i<r);
		while(a[--j]>x);
		if(i>=j) break;
		swap(a[i],a[j]);
	}
//	swap(a[l],a[j]);
a[l]=a[j];
a[j]=x;
	return j;
}
void QuickSort(int a[],int l,int r){
	if(l<r){
		int q=partition(a,l,r);
		QuickSort(a,l,q-1);
		QuickSort(a,q+1,r);
	}
}
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	QuickSort(a,0,n-1);
	cout<<a[(n-1)/2]<<endl;
}

参考代码二(stl库sort函数运用)

#include <bits/stdc++.h>
using namespace std;
int a[70000000];//!!!!把数组放外面 
int main()
{
	int n;
	cin>>n;
	
	for(int i=0;i<n;i++) cin>>a[i];
	 sort(a,a+n);
	 int res=a[(n-1)/2];
	 cout<<res<<endl;
}

拓展

快排函数的实现:

int partition(int a[],int l,int r)
{
	int i=l,j=r+1;
	int x=a[l];
	while(true)
	{
		while(a[++i]<x&&i<r);
		while(a[--j]>x);
		if(i>=j) break;
		swap(a[i],a[j]);
	}
//	swap(a[l],a[j]);
a[l]=a[j];
a[j]=x;
	return j;
}
void QuickSort(int a[],int l,int r){
	if(l<r){
		int q=partition(a,l,r);
		QuickSort(a,l,q-1);
		QuickSort(a,q+1,r);
	}
}

注意数组大的时候把数组放在外面全局定义,否则会出现Runningtime Error的问题

C 北京你好

题目描述

Description
《北京你好》主要讲述2008年8月8日北京奥运会开幕式的故事。出租车司机张北京拿到了一张奥运会开幕式门票,到处得瑟,准备留给儿子当生日礼物。可是当他准备把门票送给他的儿子时,却发现红包里的门票变成了800块钱。他赶忙回去找那个碰过他票的小子拿票。当听到小子说他来自汶川,想摸摸鸟巢里他爸装的栏杆时,张北京犹豫了一下,把票送给了那小子。奥运开幕那天张北京决定到奥运广场和大家一起看大屏幕直播的开幕式,顺路拉几个客人。在他从家到奥运广场的路上有若干个出租车停靠点,按照从小到大的顺序编号。每个停靠点会有多个人要打车到其他的停靠点。除非他不再载客,否则必须载客,不能拒载。请你帮助张北京选择一个拉客方案,使他可以拉最多的客人,但是最后一个客人的停靠点不能超过奥运广场。
Input
第一行两个数字m和n,用空格分隔,代表奥运广场的编号为m和n个客人要打车,其中出租车上落点的编号不大于120,0<m≤100, 0<n≤1000。接下来n行,每行两个数字,以空格分隔,表示客人打车的开始和结束站点
Output
一个数字,表示张北京最多可以拉多少个客人
Sample Input 1

20 7
1 7
2 3
2 5
3 5
3 7
7 11
11 22

Sample Output 1

3

Hint
载客最多的路线为2->3->7->11

基本思路

运用邻接矩阵(二维数组)保存可达路径,设数组dp[],运用动态规划,遍历该二维数组,假如可达则更新dp数组,直到遍历结束

参考代码

#include <bits/stdc++.h>
using namespace std;
int m,n;
int a[105][105],dp[105]={0};
int main()
{
	memset(a,0,sizeof(a));
	cin>>m>>n;
	while(n--)
	{
		int x,y;
		cin>>x>>y;
		if(y<=m&&x!=y)
		{
			a[x][y]=1;
			dp[y]=1;
		}
	}
	int max_res=0;
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=i-1;j++)
		{
			if(a[j][i]) dp[i]=max(dp[i],dp[j]+1);
		}
		max_res=max(max_res,dp[i]);
	}
	cout<<max_res<<endl;
}

拓展

注意二维数组的初始化方法:
memset(a,0,sizeof(a));//将二维数组a初始化为0
注意一维数组初始化为非0时不能直接={value},用遍历初始化

D 回归

题目描述

Description
《回归》主要讲述1997年7月1日香港回归的故事。香港回归,升起五星红旗的时间是关键。外交官、港警、升旗手、修表师是被时间这件事联系起来的四个角色。外交官谈判定下了升旗时间是1997年7月1日0时0分0秒,升旗手为了升旗时间锻炼自己的肌肉记忆,确保升旗速度和国歌吻合。修表师校准手表,确保手表的时间。港警则根据时间更换帽徽。女港警和修表师是夫妇。有人给修表师送来了一块用于升旗时计时的手表。修表师要把n个零件装配到手表中,尽可能保证手表的精度。每个零件有两种型号,每种型号的精度和体积不同。修表师要从每个零件中选一个型号的零件,装配到手表中,要求所有零件的体积不超过手表的容积,并且总精度最高。
Input
第一行两个数字,以空格分隔,分别代表零件的个数n和手表的容积c
接下来n行,每行四个数字以空格分隔,代表这个零件第一种型号的精度、体积和第二种零件的精度、体积
Output
最高的总精度
Sample Input 1

2 10
2 2 3 5
4 6 2 4

Sample Output 1

6

Hint
第一个选第一种,第二个选第一种

基本思路

思路一:
思路一
思路二:
该题属于分组背包问题,但分组背包问题是至多选一个,而本题为每个零件要从两个型号中选一个,不完全相同
分组背包问题:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

参考代码(思路一)

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int n,c;
	cin>>n>>c;
	vector<pair<int,int>> v;
	int a1,b1,a2,b2;
	cin>>a1>>b1>>a2>>b2;
		pair<int,int> p1(a1,b1);
		pair<int,int> p2(a2,b2);
		v.push_back(p1);
		v.push_back(p2);
	for(int i=1;i<n;i++)
	{
		//第i种零件
		cin>>a1>>b1>>a2>>b2;
		pair<int,int> p1(a1,b1);
		pair<int,int> p2(a2,b2);
		int len=v.size();
//		cout<<len<<"........."<<endl;
		for(int i=0;i<len;i++)//p1
		{
			if(v[i].second+p1.second<=c)
			{
				pair<int,int> p3(a1+v[i].first,b1+v[i].second);
				v.push_back(p3);
			}
		}
			for(int i=0;i<len;i++)//p2
		{
			if(v[i].second+p2.second<=c)
			{
				pair<int,int> p4(a2+v[i].first,b2+v[i].second);
				v.push_back(p4);
			}
		}
	}
	int max_res=0;
	for(int i=0;i<v.size();i++)
	{
		max_res=max(max_res,v[i].first);
//		cout<<v[i].first<<" "<<v[i].second<<endl;
	}
	cout<<max_res<<endl;
//	cout<<v.rbegin().first
}

拓展

pair的运用
vector的运用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GCTTTTTT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值