算法设计与分析 实验一 算法概述

第1关:数字统计问题
题目描述:

一本书的页码从自然数1开始编码直到自然数n。书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0.
例如,第8页用数字8表示,而不是08或者008之类。
数字统计问题要求对给定书的总页码n,计算出书的全部页码中分别出现了多少次数字0,1,2,…,9。

测试输入: 11

预期输出:
Please input the pagecount
11
The result is
1
4
1
1
1
1
1
1
1
1

错误思路1:
我是这样想的 比如999页 那我就三层循环遍历 然后对应数字+1


#include<stdio.h>
#include<math.h>
#include<stdlib.h>
void count(int );
int main()
{
 int pagecount;
 int i;
 printf("Please input the pagecount\n");
 scanf("%d",&pagecount);
 printf("%d\n",pagecount);
 count(pagecount);
 return 0;
}

void count(int pagecount)
{
    int a[10] = {0}; //将所有页码都清空为0 
	int tpagecount = pagecount; //设置一个替代变量
	int n = 0; //每个单位的个数
	
	while (pagecount > 0) {
		while(tpagecount > 0) {
    		n = tpagecount % 10; //求得最后一个页码
			printf("n %d\n",n);
			tpagecount = tpagecount / 10;
			printf("count %d \n",tpagecount);
		
		
			for(int i = 0; i <= 9; i++) {
				a[i]++;
			}
		
			if(tpagecount==0) {
				a[0]--;
			}
		} 
	}
    

    printf("The result is\n");
    
    for(int j = 0; j <= 9; j++) {
    	printf("%d\n",a[j]);
	}

}

正确思路:
999页 每个对应的页的每个数字都得+1 而不是单加那一个

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
void count(int );
int main()
{
 int pagecount;
 int i;
 printf("Please input the pagecount\n");
 scanf("%d",&pagecount);
 printf("%d\n",pagecount);
 count(pagecount);
 return 0;
}

void count(int pagecount)
{
    int a[10] = {0}; //将所有页码都清空为0 
	int tpagecount = pagecount; //设置一个替代变量
	int n = 0; //每个单位的个数
	
	while (pagecount > 0) {
		tpagecount = pagecount;
		while(tpagecount > 0) {
    		n = tpagecount % 10; //求得最后一个页码
    		a[n]++;
			tpagecount = tpagecount / 10;
		}
		pagecount--;
	}
    

    printf("The result is\n");
    
    for(int j = 0; j <= 9; j++) {
    	printf("%d\n",a[j]);
	}

}

第2关:字典序问题
题目描述:
在数据加密和数据压缩中长需要对特殊的字符串进行编码。给定的字母表由26个小写英文字母组成,即A={a,b,c,…,z}。该字母表产生的升序字符串是指字符串中字母从左到右出现的次序与字母在字母表中出现的次序相同,且每个字母最多出现1次。例如,a、b、ab、bc、xyz等字符串都是升序字符串。现在对字母表A产生的所有长度不超过6的升序字符串按照字典序排列并编码,编码详见教材。
请对于任意长度不超过6的升序字符串,迅速计算出它在字典中的编码。

测试输入:
2
a
b
预期输出:
1
2

代码:

方法一:迭代法

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	int k;
	scanf("%d",&k);//输入查找字典的个数 
	char dictionary[k][7]; //设置字典数组 让其装搜索字典的个数 
	int number[6] = {1,27, 52, 76, 99, 121}; //每位数的开始编码  
	
	for(int i = 0; i < k; i++) {
		scanf("%s",&dictionary[i]);
	} 
	
//	printf("%d",strlen(dictionary[0]));
	for (int j = 0; j < k; j++){ //遍历每一个字符串 
	
		int len = strlen(dictionary[j]); //求得每个字符串的长度 
		char dic =  dictionary[j][len-1]; //求得最后一个字符 
		
//		printf("%d\n",dic); 根据最后一个字符寻找对应的编码
		
		int cha = dic - 96 - len; //找到最后一个数值的编码差值 
		
//		printf("%d",cha);
		printf("%d\n",number[len-1] + cha); 
	}
 return 0;
}

方法二:递归法(还未写)

第3关:兔子问题
题目描述:
求解Fibonacci数列的第110项、第200项的值。
测试输入: 110
预期输出: 26925748508234281076009
提示:
注意溢出及大数问题
第一项为 0 ,第二项为1

代码:
错误思路:直接用递归或者循环,会因为数字过大而无法输出。

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
int Fibonacci(int n); 
int main()
{
	int n;
	int f;
	scanf("%d",&n);
	f = Fibonacci(n);
	printf("%d",f);
 return 0;
}

int Fibonacci(int n) {
	if(n == 1) 
	{
		return 0;
	}
	else if (n == 2) 
	{
		return 1;
	} 
	else {
		return Fibonacci(n-1)+Fibonacci(n-2);
	}

}

参考博客:https://blog.csdn.net/qq_40790042/article/details/119846094?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164656536416780366540178%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=164656536416780366540178&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_click~default-2-119846094.pc_search_result_control_group&utm_term=%E9%AB%98%E7%B2%BE%E5%BA%A6%E5%8A%A0%E6%B3%95&spm=1018.2226.3001.4187
自己实现的高精度加法

/**
	高精度加法 
	思路:1.首先先读入数据,然后逆序放置在数组里面 且每一步得进行减0的操作
		  2.设置一个长数组,放置加数
		  3.设置进位,然后一个一个加
		  4.最后再减去0,再倒过来输出 
**/ 
//用C++来编程 
#include<iostream>
#include<string.h>
using namespace std;
//设置逆序输入的数组 ,假设读入的数据并不长和大 数字必须得一开始为0 
int n1[100] = {0};
int n2[100] = {0};
int sum[1000] = {0};  

//写一个返回最大值的函数
int Max(int a, int b) {
	if (a > b) {
		return a;
	} 
	else {
		return b;
	}
} 

int main() {
	string a;
	
	//输入相加数据,并将其倒序
	cout << "请输入需要相加的数字1" << endl;
	cin >> a;
	int n1Length = a.length();

	for (int i = 0; i < a.length(); i++) {
		n1[i] = a[a.length()-i-1] - '0';
	} 
	
	cout << "请输入需要相加的数字2" << endl;
	cin >> a;
	int n2Length = a.length();

	for (int i = 0; i < a.length(); i++) {
		n2[i] = a[a.length()-i-1] - '0';
	} 
	
	//输出测试 
//	for (int i = 0; i < a.length(); i++) {
//		cout << n1[i]; 
//	}
//	for (int i = 0; i < a.length(); i++) {
//		cout << n2[i]; 
//	}

	//设置进位 进位一开始为0
	int carry = 0; 
	int j = 0; //设置计数器 
	//设置循环让 n1 和 n2 不断地相加 当大于十的时候 设置进位为1 且令其原来-10
	//还得判断两个数谁是最大的 那么循环就是这个长度+1 
	int length = Max( n1Length, n2Length) + 1;
//	cout << length; 
	//忘了进位得清零了 
	for (j = 0; j < length; j++) {
		sum[j] = n1[j] + n2[j] + carry;
		if( sum[j] >= 10 ) {
			carry = 1;
			sum[j] -= 10;
		}
		else {
			carry = 0; 
		} 
//		cout << sum[j] << endl; 
	} 
	
	//测试输出 
//	for (int i = 0; i < length; i++) {
//		cout << sum[i]; 
//	}

	
	//然后再不为0的输出就行 
	//先让长度循环指向不为0的地方就可以了
	int sum_length = 0;
	if( sum[j-1] == 0) {
		sum_length = j-1;
	}
	else {
		sum_length = j;
	}
	
//	cout << sum_length << endl;  
	for (int i = sum_length-1; i >= 0; i--) {
		cout << sum[i]; 
	}
	
}

遇到问题:

  1. C++是不可以直接读取数组的长度的,但是C++的String类是可以读取数组长度的。
  2. 在逆序输出中我遇到了问题,首先我想的方法是用一个循环遍历,当遍历到是0的时候,就返回0的上一个计数器的数,但是万一算术中出现了有0的数字,这样就很可能输出的数字不对。
    所以我采用了直接判断上一个循环输出的计数器的数。
    不过得用 j-1 而不是用j 因为for循环输出会将数字+1
    当sum[j-1] == 0 的时候 说明两个数字相加的最大一位,是没有进位的,所以我需要返回j-1
    如果不是 那么就说明有进位 那就是最高位数就是j
  3. 当我输出的时候,发现了问题,我没有将carry清0.
    如果上一位有进位,而下一位没有,那这一位就需要清0. 所以我加多了一个if else判断语句.

运用高精度加法把题目解出来

	
//将高精度加法运用于兔子问题
//求解Fibonacci数列的第110项、第200项的值。

#include<stdio.h>

//一开始想的是用一维数组去写 但是需要一直读取一维数组的长度 会让算法无穷扩大 
//这是不实际的思路
//而可以直接突破 将空间增大 但是时间复杂的降低 用二维数组!! 
int f1 = 200;
int f2 = 300;

int main () {
	int num;
	int carry = 0; 
	int sum[f1][f2] = {0};
	int i = 3; //计算斐波拉契数列相加的外循环计数器
	int j = f2 -1;//计算每行相加的计数器 
	
	scanf("%d",&num);
	
	if (num == 1) {
		printf("%d",0); 
		return 0;
	} 
	else if( num == 2) {
		printf("%d",1);
		return 0;
	}
	
	//初始化斐波拉契数列 
	sum[0][f2-1] = 0;
	sum[1][f2-1] = 1;
	
	for (i = 2; i < num; i++) {
	//外层循环 为兔子问题相加的次数
		int zero = 0;
		for (j = f2-1; j >= 0; j--)	{
			//内层循环即为相加 我看了别人的思路 还是会有很多无意义的0相加 会浪费很多循环次数
			//怎么让无意义的0 不相加呢?
			//当一直向前+五个都为0 的时候 就跳出循环  设置一个计0器
			sum[i][j] = sum[i-1][j] + sum[i-2][j] + carry;
//			cout << sum[i][j] ;
			
			if(	sum[i][j] >= 10) {
				carry = 1;
				sum[i][j] -= 10; 
			} 
			else {
				carry = 0;
			} 
			
			if(sum[i-1][j]==0 && sum[i-2][j]==0) {
				zero++; //当上一位和上两位都为0 则计0器+1 
				if( zero == 10) {
					break; //当有五个0的时候 大概率说明后面都是0 即不用再计算了。 
				}
			
			}//if 

		}//for2 
//		cout << "\n";
	}//for1
	
//	输出
	while(sum[i-1][j] == 0) {
		j++; 
	}
	
	while( j <= f2 - 1 ) {
		printf("%d",sum[i-1][j]);
		j++;
	}
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值