广东外语外贸大学2020-2021学年上学期算法分析与设计期中考试

题目详情:

任老师的单词纠错(分治)

Description
任老师是广东外语外贸大学第一个省级文科重点实验室语言工程与计算实验室的研究员。他致力于自然语言处理研究。任老师在自然语言处理的研究过程中需要对英文文本进行预处理,利用字典找出文章中有多少个拼写错误的单词。如果你对自然语言处理比较感兴趣,请先帮任老师高效地解决这个问题吧。算法复杂度要求为O(logN)
Input
第一行一个数字n,0 < n < 100000,表示字典的单词数。
后面n行,每行表示字典里的一个单词。单词按照从小到大的顺序排序。
接下来一个数字m,表示英文文章的长度。
后面m行,0 < m < 100000,每行表示文章里的一个单词

Output
一个数字,表示有多少个单词拼写错误

输入样例:

5
a
book
is
that
this
4
this
iz
a
book

输出样例:

1

提示:
Hint
可以包含头文件string,在main函数外定义全局变量string数组保存字典里的单词 string words[100000]。
字符串类型string可以直接比较大小。例如
#include
int main() {
string a;
string b:
cin >> a;
cin >> b;
if (a>b) cout << “more”;
else cout << “less”;
}

非递归算法

#include<iostream>
using namespace std;
int main(){
	int n,i,m,mid,num=0,left,right;
	string dict[100000]; //定义字典 
	string article[100000]; //定义文章 
	cin>>n;
	for(i=0;i<n;i++) // 输入n个字典单词 
		cin>>dict[i];
	cin>>m;
	for(i=0;i<m;i++) // 输入m文章的单词 
		cin>>article[i];
	for(i=0;i<m;i++){
		left = 0;	// 初始化左边界 
		right = n-1; // 初始化右边界 
		while(left <= right){ //只要 左边界不大于右边界就一直执行 
			mid = (left + right) / 2; //取出当前查找范围的中间的位置
			if(article[i]==dict[mid]) break; //如何相等,则表示在字典中找到了当前的单词,当前单词拼写正确,就不用再继续查找下去,直接break 
			else if (article[i] > dict[mid]) left = mid + 1; //文章中的词比字典的词大,则表示要找的词在字典的右半区域,则left=mid+1,去右半边寻找 
			else right = mid - 1; //文章中的词比字典的词小,则表示要找的词在字典的左半区域,则right=mid-1,去左半边寻找 
		}
		if(left > right) num++; //如果是因为找到了而跳出循环的,则 left <= right,如果是没找到跳出循环则left > right,sum加1 
	}
	cout<<num;
} 

递归算法

#include<iostream>
using namespace std;
string dict[100000]; //定义字典 
string article[100000]; //定义文章 
int find(int left, int right,string str){	//left表示当前搜索范围的左边界 right表示当前搜索范围的右边界 str用于存放当前我要查找的单词 
	int mid = (left + right) / 2;   //求当前搜索范围的中间位置 
	if(left > right) return 0;  //如果当前搜索范围的左边界left>右边界right,则表示没搜索到,这个词是拼错了的返回0 
	if (dict[mid]==str) return 1; //如果相等,则表示在字典中找到了要搜索的词,拼写正确返回1 
	else if(dict[mid] > str) return find(left , mid - 1,str); //如果dict[mid] > str,表示str位于当前搜索范围的左半区域,则递归调用find(left , mid - 1,str);搜索左半区域 
	else return find(mid + 1, right,str);//如果dict[mid] > str,表示str位于当前搜索范围的左半区域,则递归调用find(mid+1,right,str);搜索右半区域
} 
int main(){
	int n,m,i,sum=0;
	cin>>n;
	for(i=0;i<n;i++) //循环输入n个字典单词 
		cin>>dict[i];  
	cin>>m;
	for(i=0;i<m;i++)
		cin>>article[i]; //循环输入m个文章单词 
	for(i=0;i<m;i++) //遍历每个article中的单词,都去调用一次find 
		if(!find(0,n-1,article[i])) sum++; //如果单词拼写错误,没有找到,那么 find(0,n-1,article[i])返回值为0,!find(0,n-1,article[i]) 为1 ,此时sum+1 
	cout<<sum;
}

刘老师的工作安排(Description

刘老师是软件工程系的主任,为了给同学们创造良好的学习条件,每天要处理很多系里的事务。事情太多,就容易忘记。刘老师早早地来到学校,从早晨8点钟开始一直忙碌到下午6点钟,一共600分钟。处理每件事务,需要不同的分钟数。请你帮刘老师计划一下,在忙碌了一天后,他没有处理的事务数越少越好。
Input
第一行一个数字n,0 < n < 100, 表示n件事务
后面n行,表示处理每件事务所需的时间

Output
一个数字,表示没有处理的最少事务数
输入样例1:
Sample Input 1

6
100
60
200
300
90
500

Sample Output 1

2

提示:
Hint
排序可以包含头文件algorithm,用sort函数

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
	int totalTime = 600; //定义总工作时间 
	int things[100]; //定义事情数组,存放所有事情 
	int n,i;
	cin>>n; 
	for(i=0;i<n;i++)  //循环输入所有事情 
		cin>>things[i];  
	sort(things,things+n); //使用sort函数对事情进行排序,从小到大排序 
	for(i=0;i<n;i++){  //进行贪心选择:每次都先选时长最小的,这样可以完成工作的数量肯定是最多的,所以剩余未完成的肯定是最少 
		if(totalTime >= things[i]) totalTime-=things[i];  //如果总工作时长比当前任务大,则说明可以完成这个任务,则总工作时长减去当前任务的时长
		else break; //如果总工作时长比当前任务小,则说明无法完成,跳出循环 
	}
	cout<<n-i<<endl; //i表示的是可以完成的工作数量,n-i就是未完成的数量 
} 

**

郑老师的代码查重(动态规划)


Description
《算法设计与分析》课程又迎来了一年一度热闹非凡的期中考试。同学们都信心满满地走进考场,坐在电脑前,十指翻飞,展示自己强悍的编码能力。这时候,最紧张的不是考试的同学,而是监考的老师。不仅担心考试系统出问题,而且担心有些同学违反考试纪律。于是郑老师安排同一个班级的同学分开做,考试期间不允许上厕所,考试结束后还会对同学们提交的代码进行查重。如果两份代码完全雷同,事情就很简单,只要比较代表代码的两个字符串是否完全一样就可以了。但是有些同学会自作聪明地修改一下代码而不影响程序的正常运行。例如如下两段代码,运行结果一样。
int a,b;cin>>a;cin>>b;cout<<a+b
int c,d,e;cin>>c>>d;cout<<c+d;
怎么才能发现这种情况呢?郑老师额头上的头发又掉了很多。他忽然想到这个问题可以用求最长公共子序列的方法求解。定义相似度为最长公共子序列的长度占较短字符串的百分比。如果相似度超过75%,就认为作弊。为了拯救郑老师的头发,请你帮他完成这个程序吧。

Input
两行,每行一个字符串,字符串只包含普通的字符,已经去除了空格。字符串长度小于1000

Output
计算两个字符串的相似度,如果大于75%,输出相似度和“Yes“,否则输出相似度和”No“,中间用一个空格分隔。相似度直接取整数部分,忽略小数部分

Sample Input 1

inta,b;cin>>a;cin>>b;cout<<a+b;
intc,d,e;cin>>c;cin>>d;cout<<c+d;

Sample Output 1

80% Yes

Hint
第一段代码长度31, 第二段代码长度33, 最长公共子序列长度为25, 25
100/31=80。超过75%,所以输出“Yes”*

#include<iostream>
using namespace std;
int c[1000][1000]; //c[i][j]用来存储 Xi到Yj的最长公共子序列长度 
void MaxLength(int m,int n,string x,string y){ //m,n分别表示字符串x和字符串y的长度 
	int i,j; 
	for(i=1;i<=m;i++) //当j为0的时候,空序列是Xi到Yj的最长公共子序列,所以赋值0 
		c[i][0]=0;
	for(i=1;i<=n;i++) //当x为0的时候,空序列是Xi到Yj的最长公共子序列,所以赋值0
		c[0][i]=0;
	for(i=1;i<m;i++){  
		for(j=1;j<n;j++){ 
			if(x[i]==y[j]){  // 当 Xi==Yj 时,c[i][j]=c[i-1][j-1]+1 
				c[i][j] = c[i-1][j-1] + 1;
			}
			else c[i][j]=max(c[i-1][j],c[i][j-1]); // 当 Xi!=Yj 时,c[i][j]=max(c[i-1][j],c[i][j-1])
		}
	} 
}
int main(){
	string x,y;
	cin>>x>>y;
	int m=x.length();  // 得到字符串x的长度 
	int n=y.length();   // 得到字符串y的长度 
	int MinLength = min(m,n); // 求出较短字符串的长度 
	MaxLength(m,n,x,y); 
	int precent=0; 
	if(c[m-1][n-1]!=0){ //因为字符串都是以'\n'结尾的,所以不管怎么样,x[m]==y[n]=='\n',两个字符串的最小公共子序列都会是1,所以我们要求x[0;m-1]和y[0;n-1]有无公共子序列,若有则才是真的有公共子序列,且c[m][n]=c[m-1][n-1]+1,则此时算出相似度,若x[0;m-1]和y[0;n-1]没有,则就无公共子序列,相似度precent=0 
	c[m][n]=c[m-1][n-1]+1;
	precent = (c[m][n]*100) / MinLength;
	}
	else precent = 0;
	if(precent > 75){
		cout<<precent<<"% "<<"Yes";
	}
	else cout<<precent<<"% "<<"No";
} 

**

巫老师的购物计划(动态规划)

**

Description
巫老师是多年讲授算法的美女老师,同时她也是一个购物达人。双十一刚刚过去,她看着购物网站里的一个个订单,满满地满足感。每年这个时候最让她头疼的事情就是凑单。她早早地把想要购买的物品加入了购物车。购物网站推出了各种满减优惠,满100减20,满300减100。为了得到最大的实惠,巫老师需要用购物车里的商品凑够满减的金额,而且超出的金额最少越好。你能帮巫老师解决这个难题,让她明年这个时候更开心吗?

Input
第一行,一个整数m,0 < m < 1000,表示需要凑够的金额
第二行,一个整数n,0 < n < 100, 表示购物车里的商品数
后面n行,每行一个整数,表示商品的价格
Output
满足满减金额的最小金额。如果凑不够满减金额,输出-1

Sample Input 1

100
5
200
50
70
40
80

Sample Output 1

 
110

Hint
样例选择的商品为70+40=110

#include <iostream>
#include <cstring>
using namespace std;
int m, n;
int p[103];
int dp[102][1003];  //dp为与满减金额的差距
int main() {
    cin >> m >> n;
    int sum = 0;
    for (int i = 1; i <= n; ++i) {
        cin >> p[i];
        sum += p[i];
    }
    //判断商品总金额是否符合满减条件
    if (sum < m) {
        cout << -1;
        return 0;
    }
    //初始化 dp[i][j]
    memset(dp,-m, sizeof(dp));
    // i 为第几件商品
    for (int i = 1; i <= n; ++i) {
        // j 为所选择的商品总金额
        for (int j = 1; j <= sum; ++j) {
            if (j < p[i]) dp[i][j] = dp[i - 1][j]; //放不下的情况 
            else if (j == p[i]) dp[i][j] = p[i] - m; //刚好放得下 
            else if (dp[i - 1][j] < 0 || dp[i][j - 1] < 0) 
                    dp[i][j] = max(dp[i - 1][j], max(dp[i][j - 1], dp[i - 1][j - p[i]] + p[i]));
            else dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]);
        }
    }
    cout << dp[n][sum] + m;
    return 0;
}

原题来自广东外语外贸大学的OJ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值