“蓝桥杯”模拟法(一)——日期问题(2017年试题G)

梁老师
梁老师 北京小升初老师~

0 人点赞了该文章 · 59 浏览





1.模拟法简介

模拟法,顾名思义,就是利用计算机模拟问题的求解过程,从而得到问题的解。模拟法由于简单,因此又被称为“不是算法的算法”。
模拟法是学习算法的基础,通过模拟可以学习编程的各类技巧,提升初学者建立各种编程逻辑模型的感觉。大部分模拟题目直接模拟就可以求解,还有少量模拟题目需要考生简化模拟过程,否则可能会使逻辑复杂,导致求解用时过长。
模拟法适用于问题求解清晰、运算规模较小的问题。如果问题求解的时空代价很大,就要考虑是否有其他更好的解决方案。

2.【案例解析】不高兴的津津

津津上初中了。妈妈认为津津应该更加用功地学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班。另外,妈妈每周还会送她去学习朗诵、舞蹈和钢琴。但是津津如果一天上课超过8小时就会不高兴,而且上得越久就越不高兴。假设津津不会因为其他事不高兴,并且她的不高兴不会持续到第二天。请你帮忙检查津津下周的日程安排,看看她下周会不会不高兴;如果会,那么她哪天最不高兴。
输入包括7行数据,分别表示周一到周日的日程安排。每行包括两个小于10的非负整数,用空格隔开,分别表示津津在学校上课的时间和妈妈安排她上课的时间。
输出一个数字。如果津津不会不高兴,则输出0,如果会,则输出最不高兴的是周几(用1,2,3,4,5,6,7分别表示周一,周二,周三,周四,周五,周六,周日)。如果有两天或两天以上不高兴的程度一样,则输出时间最靠前的那一天。
例如,输入下列数据:
5  3
6  2
5  3
5  4
0  4
0  6
则输出为3。
本题可以采用模拟方法依次判断哪天最不高兴,并将最不高兴的那.天输出,在输出过程中要注意以下几个问题。
(1)判断n个数中的最大值

max= 0;
for (i=1;i<=n;i++) //输入n个数据
{
cin>>a;
if (a>max)
max=a; 
}

(2)数据存储问题
本题的数据一共有7组,不算多,也不算少,可以直接运算,也可以将数据存储到数组后再进行计算。
若不采用数组,则模拟的过程如下:

int a,b,s,max=0, i,day=0;
for (i=1;i<=7;i++)
{
cin>>a>>b;
s=a+b;
if ((s>max) && (s>8))
{max=s,day=i; }
}
cout<<day<<endl;

如果采用数组,则可以将数据存储起来,在后续的操作中会更加方便,也更容易理解,采用数组模拟的方法如下:

int a,b, i, day, max, array[8];
char c;
for(i=1;i<=7;i++)
{
cin>>a>>b;
array[i]=a+b;
}
max=array[0];
for(i=1;i<=7;i++)
{
if (max<array[i])
{
max=array[i];
day=i;
}
if (max>8)
cout<<day<<endl;
else
cout<<0<<endl;

模拟法一般都不,但也会考查一些基础算法,例如本题考查了如何在n个数中求最大值,及如何判断津津的不高兴条件。

3. 本次程序练习——日期问题(2017年试题G)(答案见下期)

【问题描述】
小明正在整理一批文献,这些文献中出现了很多日期,小明知道这些日期都在1960年1月1日至2059年12月31日之间。令小明头疼的是,这些日期采用的格式非常不统一,有采用“年/月/日”的,有采用“月/日/年”的,还有采用“日/月/年”的。更加麻烦的是,年份都省略了前两位,使得文献上的一个日期存在很多可能的日期与其对应。
例如02/03/04,可能是2002年03月04日、2004年02月03日或2004年03月02日。给出一个文献上的日期,你能帮助小明判断有哪些可能的日期与其对应吗?
[输入格式]
一个日期,格式是" AB/CD/EF" (0≤A,B,C,D,E,F≤9)。
[输出格式]
输出若干个不相同的日期,每个日期一行,格式是"yyyy- mm-dd"。多个日期按从早到晚的顺序排列。
[样例输入]
02/03/04
[样例输出]
2002-03-04
2004-02-03
2004-03-02
提示:
本题的思路很简单,将输入的3个数据分别进行年、月、日的合法判断,如果合法就输出。但是求解本题要注意以下两点。
(1)月份数据的表示
由于每月的天数没有规律性,所以最好的方法就是利用数组将每月的天数表示出来,如:
int days[13]={0, 31, 28,31, 30,31, 30, 31, 31, 30,31, 30, 31};
这里还要注意闰年的问题,如果是闰年,则2月的数据就会不同,可以采用另个数组存储,如:
int leapdays [13]={0,31, 29,31, 30, 31,30,31,31,30,31,30,31};
(2)合法年、月、日的存储
对于一组数据, 可能会出现重复的合法年、月、日。例如,输入01/01/01,则3组合法数据都是2001-01-01,所以这里要去重复。
(3)多个日期按从早到晚输出。

4.上期参考答案

练习6 分解质因数
参考程序一——吴炳毅的答案

#include <iostream>
using namespace std;
int isPrime(int n)  //判断是否为质数函数
{
 int num=0;
  for(int k=2;k<=n;k++)
  {
   if(n%k==0)return 1;
  }
  return 0;
}
int primefactors(int m)  //计算一个数的质因数
{
 int c=0;
 for(int j=2;j<=m;j++)
 {
   while(m%j==0&& isPrime(j))
  {
   c++;
   m=m/j;
  }
}
}
return c; 
}
int main() 
{
 int a,b;
 cout<<"input a and b:";
 cin>>a>>b;
 int sum=0;
 for(int i=a;i<=b;i++)
  sum+=primeFactors(i);
 cout<<sum<<endl;
}

参考程序二——申茂生答案

#include <iostream>
using namespace std;
int nextprime(int a)//输出下一个质数 
{
 while(true)
 {
  int f=0;
  a++;
  for(int i=2;i<=a/2;i++)
  {
   if(a%i==0)
   {
    f=1;
    break;
   }
  }
  if(f==0)
   return a;
 }
}
int main()
{
 int a,b,sum1=0;
 cin>>a>>b;
 for(int i=a;i<=b;i++)//从a到b的范围 
 {
  int sum2=0;
  for(int j=2;j<=i/2;j=nextprime(j))//j为质数,若j整除i,则j为质因数 
  {
   int c=i;
   while(c%j==0)//判断j的冥次方是否整除i 
   {
    sum2++; 
    //去注释可看质因数整除i过程cout<<c<<' '<<j<<' '<<sum1+sum2<<endl;
    c/=j;
   }
  }
  if(sum2==0)//若sum2为0则说明i为质数,可以整除本身 
   sum2=1;
  sum1+=sum2;
 }
 cout<<sum1;
}

练习7:回文数  参考程序

#include <iostream>
#include <cmath> 
//#include <string> 
using namespace std;
string rev(string s) // 字符串逆置
{
 string ss(s.rbegin(),s.rend());
 return ss; 
 } 
bool isPalindrome(string str)  //判断字符串是否为回文 
{  
    //rbegin() 返回一个逆向迭代器,指向字符串的结尾(第一个字符的前一个位置)。
    // rend(); 返回一个逆向迭代器,指向字符串的开头(第一个字符的前一个位置)。
 string rStr(str.rbegin(),str.rend());
 if(str==rStr)
  return true;
 else
  return false;
}
int swapDec(string str,int r)//r进制字符串向十进制数转换
{
 int len=str.length();//字符串的长度
 int num=0//十进制数
 for(int i=len-1;i>=0;i--)
 {
  //把数字字符转换成数值数据
  int n;
  if(str[i]>='A'&&str[i]<='F'
   n=str[i]-'A';
  else if(str[i]>='a'&&str[i]<='f')
       n=str[i]-'a';
  else n=str[i]-'0';
  num+=n*pow(r,i);
  } 
  return num;
 } 
 
 string  swapR(int n,int r) //十进制数转换为r进制的字符串
 
{
  string str="";//r进制字符串 
  while(n)
  {
   string t;
     int m=n%r;
     switch(m)
     {
      case 10: t="A"break;
      case 11: t="B"break;
      case 12: t="C"break;
      case 13: t="D"break;
      case 14: t="E"break;
      case 15: t="F"break;
      default:t=m+'0'//整型转换成字符串 
  }
    str=t+str; //拼接字符串 
    n=n/r; //修改n的值 
   } 
 return str; 
 } 
int main()
{
 int n; //进制 
 string m;//数据 
 cout<<"input n:";
 cin>>n;
 cout<<"input m:";
 cin>>m; 
 int counts=0;
 while(!isPalindrome(m)) //如果m不是回文
 {
  int x=  swapDec(m,n);//x是m的十进制数
  int y=  swapDec(rev(m),n);//y是m的逆序串的十进制数;
  int z=x+y;//z是两个数的和
  m=swapR(z, n) ;// 修改m的值,接着去检查m是否为回文 
  counts++;//计数器加1;
  if(counts>30) { //大于30次,则退出循环 
   break;  
   counts=-1;
  }
  } 
    cout<<counts<<endl;
 return 0;
}

图片


添加 家长论坛微信 



发布于 2024-04-26 18:21

免责声明:

本文由 梁老师 原创发布于 家长帮 ,著作权归作者所有。

登录一下,更多精彩内容等你发现,贡献精彩回答,参与评论互动

登录! 还没有账号?去注册

暂无评论

广告
All Rights Reserved Powered BY WeCenter V4.1.0 © 2025 京ICP备20005761号-2