函数和递归练习题

A - 古老的密码

题意:字符串加密,一种方式是通过把一种字母转换为另一种(可以相同)字母,另一种方式是把字符串的各个字符按照一个新的排列构成一个新的字符串;由于单一的加密方式强度过低,采用两种方式结合的方式加密,每组测试用例给出两个字符串,判断一个字符串是否能通过上述加密手段得到另一个字符串。

分析:

若加密,则同属于一类字符的字符个数固定不变(加密前后都是如此),打乱顺序也是如此。

第一种加密,一种字符变成另一种(或相同)的字符,例如’A’->’Y’,那么字符串中所有’A’都要变成’Z’;第二种,改变字符串中各字符的排列,这两种方式可能改变了字符串的形态,但各自字符串的组成元素的数量是相同的,这样,我们就可以根据这一固定属性每种字符的数量来判断是否加密。

#include<iostream>
#include<algorithm>
using namespace std;
bool check(string& a, string& b) {
	int num1[26] = { 0 }, num2[26] = { 0 };
	int l = a.length();
	for (int i = 0; i < l; i++) {//遍历字符串,把各字符串中所有字符出现的次数统计出来
		num1[a[i] - 'A']++;//统计a字符串中各个字符的数量
		num2[b[i] - 'A']++;//统计b字符串中各个字符的数量
	}
	bool flag = false;
	sort(num2, num2 + 26);//对其进行排序
	sort(num1, num1 + 26);
	for (int i = 0; i < 26; i++) {//比较排序后两个数组各个数据是否相同,即通过比较字母数是否一致判断另一字符串是否是通过加密得到的
		if (num1[i] != num2[i])return 0;//不一致,那么肯定不能通过加密得到
	}
	return 1;//返回true
}
int main() {
	string s1, s2;
	while (cin >> s1 >> s2) {
		if (check(s1, s2))printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}

B - 刽子手游戏

题意:猜字母,参赛者需要猜测给出的谜底中的所有字母,每猜对一个,谜底中对应的该字母都算猜中,即同类字母都算被猜到了,每猜错一次,刽子手就会在图纸上划一笔,累计画完7笔,参赛者就输了,如果在画完之前猜出所有谜底,则参赛者获胜,如果参赛者猜出足够字符来决定输或者赢,则参赛者退出。

分析: 用字符串数组保存三种结果输出;标记谜底中所有字符,统计不同字符的数量,即谜底中字符的种类数,对照参赛者的猜测结果,如果猜到了一种,谜底中剩余未被猜出字符个数减一,猜错了,错误次数加一,全部猜对了,返回0,猜错次数累计7次,返回1,没有输赢,返回2.

#include<iostream>
using namespace std;
int check(string& a, string& b) {//a为答案,b为猜侧值
	int total = 0;//统计当前还有多少种字符没有被猜出
	int wrong = 0;//记录当前猜错次数
	int num1[26] = { 0 }, num2[26] = { 0 };//num[i]统计字符'a'+i是否出现过
	for (int i = 0; i < a.length(); i++)num1[a[i] - 'a']++;//统计字符种类,也可以num1[a[i]-'a']=1,反正就是标记一下
	for (int i = 0; i < 26; i++)if (num1[i])total++;//统计答案中字符种类
	for (int i = 0; i < b.length(); i++) {//遍历b字符串中各个字符
		if (!num2[b[i] - 'a']) {//如果b中还没猜过该字符
			if (num1[b[i] - 'a']) {//如果a中该字符出现过,猜对一次,剩余未猜中字符数total减一,猜完返回0,str[0]=win
				total--;
				if (total == 0)return 0;
			}
			else if (!num1[b[i] - 'a']) {//当前猜测的字符未在a中出现,说明猜错了,记录猜错次数,达到7次则猜数失败,返回1,str[1]=lose
				wrong++;
				if (wrong >= 7)return 1;
			}
		}
		num2[b[i] - 'a'] = 1;//标记当前字符已经猜过了,避免重复统计
	}
	return 2;//猜完未错也未对,出局,str[2]=chicked out
}
int main() {
	int n;
	string s1, s2;
	string str[] = { "You win.","You lose.","You chickened out." };//三种情况
	while (~scanf("%d", &n) && n != -1) {
		printf("Round %d\n", n);
		cin >> s1 >> s2;
		cout << str[check(s1, s2)];//通过check()函数返回值作为下标直接输出对应游戏结果
		printf("\n");
	}
	return 0;
}

C - 救济金发放

 

题意:N个救济金申请人围一圈,按逆时针编号为1~N,一名官员从1开始逆时针方向数k名,另一名官员从N开始顺时针数m名,被选中的两个申请人被送去培训,如果两个官员选到了同一个申请人,那个申请人会被送去当政治家,每个工作人员再次开始计数下一个可用的人,直到没有人剩余。注意两名申请人同时离开这个圈,一名官员可能会选中被另一面官员选中的人(即两名官员可以选中同一个人)

分析:逆时针编号1~N,一名官员按逆时针访问这些人围成的圈,选中他数到的第k名,另一面官员顺时针访问,选中数到的第m名,就是两次约瑟夫环问题嘛,一遍顺着编号,一遍逆着编号,两个官员都确定了选择的人之后,被选择的人退出圈子,继续下一轮查找,直到所有人都被选中,结束。选中的人打个标记,表示已经选过了(出圈),下一次就直接跳过他,不计数,先确定一个官员的选择对象,做个标记,此时这个被选中的人还没有出圈,他也可以被第二个官员选中,再确定另一个官员选中的人,如果选的一样,就出圈一个人,否则出圈两个人。

#include<iostream>
#include<vector>
using namespace std;
int main() {
	int N, n, m;
	while (~scanf("%d %d %d", &N, &n, &m)) {
		if (!N && !n && !m)break;
		vector<int>a(N + 1);//1~N;
		int i = 1, j = N;
		int c1 = 0, c2 = 0;//分别记录i查找和j查找的有效次数 
		int ans = 0;//记录当前已经挑选了几人 
		int same = 0;//记录第一次找到的人的编号,因为两次查找可以找同一个人,但第一次找到的人因为被选中,已经被打上标记了,第二次查找中可能会跳过这个人,然而用same记录,标志这个人可以被选中
		bool flag = 0;//标记两次选人是否选择到同一个人身上
		while (ans < N) {
			//cout<<endl;cout<<i<<endl;printf("c1:%d\n",c1);//
			while (1) {//约瑟夫环,间隔n(题目中为k),逆时针,也就是顺着编号
				if (!a[i])c1++;
				if (c1 % n == 0) {
					a[i] = 1; same = i; c1 = 0; break;//一次有效间距查找完成后,c1清0; 
				}
				i = i % N + 1;//1~N;
			}
			//cout<<i<<endl;//
			//cout<<j<<endl;//
			while (1) {//顺时针,间隔m,逆着编号
				if (!a[j] || j == same)c2++;//没有被挑选走或者与当前的i(same)是同一个数,都算一次有效查找 
				if (c2 % m == 0) {
					if (j == same)flag = true;
					else a[j] = 1;
					c2 = 0;//一次有效间距查找完成后,c2清0 
					break;
				}
				j = (j - 1 + N - 1) % N + 1;//1~N;
			}
			//cout<<j<<endl;//
			if (flag) {
				printf("%3d", same); ans++;
				flag = false;//flag状态清零 
			}
			else { printf("%3d%3d", i, j); ans += 2; }
			same = 0;//一次进行两种查找,完成后本轮查找的same已经被调用过了 ,需要重新更新以便下一轮查找使用 
			if (ans < N)printf(",");//后续还有人未被挑选,打印后缀','
			else break;//ans>=N,所有人都被挑选完了,任务完成
			while (a[i])i = i % N + 1;//查找下一个未被挑选的i,作为下一次循环查找的出发点 
			while (a[j])j = (j - 1 + N - 1) % N + 1;//查找下一个未被挑选的j ,作为下一次查找的出发点
		}
		printf("\n");
	}
	return 0;
}

D - 最大质因子序列

#include<stdio.h>
int isPrime(int n)
{
    if(n<2) return 0;
    int i;
    for(i=2;i<=n/i;i++)
    {
        if(n%i==0) return 0;
    }
    return 1;
}
int g(int n){
	if(isPrime(n)==1)
		return n;
	int i;
	for(i=n-1 ; i>1 ; i--){
		if(n%i==0&&isPrime(i)){
			return i;
		}
	}
}
int main()
{
	int a,b,i;
	scanf("%d%d",&a,&b);
	for(i = a ; i<b ; i++){
		printf("%d,",g(i));
	}printf("%d",g(b));
	return 0;
} 

E - 求 f(x,n)

#include <stdio.h>
#include <math.h>
float f(float	 x, float n ){
	if(n==1){
		return sqrt(n+x);
	}
	return sqrt(n+f(x,n-1));
}
int main(int argc, char *argv[])
{
	float x,n;
	scanf("%f %f",&x,&n);
 	printf("%.2f",f(x,n));
	return 0;
}

 

F - 再求 f(x,n)

 

#include <stdio.h>
#include <math.h>
float f(float x, float n ){
	if(n==1){
		return x/(x+n);
	}
	return x/(n+f(x,n-1));
}
int main(int argc, char *argv[])
{
	float x,n;
	scanf("%f %f",&x,&n);
 	printf("%.2f",f(x,n));
	return 0;
}

 

 G - M Function G

#include<bits/stdc++.h>
using namespace std;
long long n;
const int N=1e6+5;
long long a[N];
long long M(int l,int r){
	if(abs(r-l)<=5){
		int max=a[0],i;
		for(i=l;i<=r;i++)
		{
			if(a[i]>max) max=a[i];
		}
		return max;
	}else{
		long long t=(l+r)/2;
		return M(l,t)%max(M(t+1,r),(long long) 7)+a[t]-1;
	}
}
int main()
{
	scanf("%lld",&n);
	for(long long i=1;i<=n;i++)
	scanf("%lld",&a[i]);
	printf("%lld",M(1,n));
}

H - 闰年展示 

#include <stdio.h>
int f(int n){
	if(n%4==0&&n%100!=0||n%400==0){
		return 1;
	}
	return 0;
}
int main()
{
	int a,b,i,c=0,p[3000];
	scanf("%d%d",&a,&b);
	for(i=a ; i<=b ; i++){
		if(f(i)){
			p[c]=i;
			c++;
		}
	}
	if(c==0)
		printf("%d\n",c);
	else{
		printf("%d\n",c);
	for(i=0 ; i<c-1 ; i++){
		printf("%d ",p[i]);
	}
		printf("%d",p[c-1]);
	}	
	return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值