第5章 基础题目选解

学习目标:

     学会用常量表简化代码

     学会用状态变量辅助字符串读入

     学会用结构体定义高精度证书,并设计构造函数、复制构造函数和输入输出方法

     学会为结构体定义“小于”运算符,并用它定义其他比较运算符

     熟悉掌握冒泡排序和排序检索

     熟练掌握用qsort库函数给整数和字符串排序的方法

     熟练掌握小规模素数表的构造方法

     熟练掌握素因子分解的方法

     熟练掌握三角形有向面积的意义和计算方法

     完成一定数量的编程练习

5.1.1  WERTYU

     把手放在键盘上时,稍不注意就会往右错一位。这样的话,Q会变成W,J会变成K等。输入一个错位后敲出的字符串,输出打字员本来想打出的句子。

     样例输入:Q S, GOMR YPFSU/

     样例输出: I AM FINE TODAY.

代码:

#include<stdio.h>
#include<string.h>
char *s="`1234567890-=QWERTYUIOP[]\ASDFGHJKL;'ZXCVBNM,./";//定义一个常数数组 
int main()
{
    int i;
    char c;
    while((c=getchar())!=EOF)
    {
        for(i=1;s[i]&&s[i]!=c;i++);//此处的;千万不可以省去 
           if(s[i])
              putchar(s[i-1]);
            else putchar(c); 
    }
    return 0; 
} 

5.1.2  TeX 括号
    在TeX中,左双引号是"。输入一篇包含双引号的文章,你的任务是把它转换成TeX的格式。

    样例输入:

    "To be or not to be,"quoth the Bard,"that is the question".

    样例输出:

    “To be or not to be,"quoth the Bard,“that is the question".

代码:

#include<stdio.h>
int main()
{
    int c,q=1;
    while((c=getchar())!=EOF)
    {
        if(c=='"')
        {
            printf("%s",q?"":"''" );
            q=!q;
        }
        else printf("%c",c);
    }
    return 0;
} 

5.1.3 周期串

如果一个字符串可以有某个长度为k的字符串重复多次得到,我们说该串以k为周期。例如,abcabcabcabc以3为周期(注意,它也以6和12为周期)。输入一个长度不超过80的串,输出它的最小周期。

     样例输入:HoHoHo

     样例输出:2

代码:

#include<stdio.h>
#include<string.h>
int main()
{
    int i,k,j;
    char word[100];
    scanf("%s",word);
    int len=strlen(word);
    for(i=1;i<=len;i++)
        if(len%i==0)
        {
            k=1;
            for(j=i;j<len;j++)
                if(word[j]!=word[j%i])
                {
                    k=0;
                    break;
                }
             if(k!=0)
             {
                 printf("%d
",i);
                 break;
             }
        }
    return 0;
}

5.2.1 小学生算术

    很多学生在学习加法时,发现“进位”特别容易出错,你的任务是计算两个整数在相加时需要多少次进位。你编制的程序应当可以连续处理多组数据,知道读到两个0(这是输入结束标记)。假设输入的整数都不超过9个数字。

   样例输入:

   123 456
   555 555
   123 594

   0     0

   样例输出:

   0
   3

   1

代码:

#include<stdio.h>
int main()
{
    int a,b;
    while(~scanf("%d %d",&a,&b))
    {
        if(a==0&&b==0)
           break;
        int c=0,ans=0;
        for(int i=9;i>=0;i--)
        {
            c=(a%10+b%10+c)>9?1:0;
            ans+=c;
            a/=10;
            b/=10;
        }
        printf("%d
",ans);
    }
    return 0;
}

5.2.2 阶乘的精确值

     输入不超过1000的正整数n,输出n!=1×2×3×……×n的精确结果。

     样例输入: 30

     样例输出: 265252859812191058636308480000000

代码:

#include<stdio.h>
#include<string.h>
const int maxn=3000;//const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是像#define一样给出的是立即数,
//所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干份拷贝。 
int f[maxn];
int main()
{
    int i,j,n;
    scanf("%d",&n);
    memset(f,0,sizeof(f));
    f[0]=1;
    for(int i=2;i<=n;i++)
    {
        int c=0;
        for(j=0;j<maxn;j++)
        {
            int s=f[j]*i+c;
            f[j]=s%10;
            c=s/10;
        }
    }
    for(j=maxn-1;j>=0;j--)
        if(f[j])  break;
    for(i=j;i>=0;i--)
        printf("%d",f[i]);
    printf("
"); 
    return 0;
}

!!!!高精度运算类bign

代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>
#include <vector>
#include <list>

using namespace std;

const int maxn = 1000;

struct bign
{
       int len, s[maxn];  //s是逆序存储
       
       bign(){ memset(s, 0 , sizeof(s)); len = 1 ; } //构造函数
       
       bign(int num) { *this  = num ; } //初始化
       
       bign(const char* num) { *this = num ; }
        
       string str() const//转换为字符串 
       {
           int i;
           string res = "";
           for( i = 0 ; i < len ; i++ ) 
               res = (char)( s[i] + '0' ) + res ;
           if (res == "") res = "0";
           return res;
       } 
        
       bign operator = (const char* num)//赋值运算1 
       {
            int i;
            len = strlen(num);
            for( i = 0 ; i < len ; i++ )
                s[i] = num[len-i-1] - '0' ;
            return *this; 
       } 
       
       bign operator = (int num)//赋值运算2 
       {
            char s[maxn];
            sprintf(s , "%d" , num);
            *this = s;
            return *this;
       } 
       
       bign operator + (const bign& b) const//加法 
       {
            bign c;
            c.len = 0;
            int i, g;
            for( i = 0 , g = 0 ; g || i < ( len > b.len ? len : b.len ) ; i++ )
            {
                 int x = g ;
                 if( i < len ) x += s[i] ;
                 if( i < b.len ) x += b.s[i] ;
                 c.s[c.len++] = x % 10 ;
                 g = x / 10 ;
            }
            return c;
       }
       
       //比较的前提是两个数都没有前导零 
       bool operator < (const bign& b) const
       {
            if( len != b.len ) return len < b.len ;
            int i;
            for( i = len-1 ; i >= 0 ; i-- )
                if( s[i] != b.s[i] ) return s[i] < b.s[i];
            return false;
       }
       bool operator > (const bign& b) const { return b < *this; }
       bool operator <= (const bign& b) const { return !(b < *this); } 
       bool operator >= (const bign& b) const { return !(*this < b); } 
       bool operator != (const bign& b) const { return b < *this || *this < b; } 
       bool operator == (const bign& b) const { return !(b < *this) || !(*this < b); }  
};

istream& operator >> (istream &in , bign& x)//定义<<运算符 
{
         string s;
         in >> s;
         x = s.c_str();
         return in;
}
ostream& operator << (ostream &out , const bign& x)//定义>>运算符 
{
         out << x.str();
         return out;
}


 5.3.1 6174问题

    假设你有一个各种数字互不相同的四位数,把所有数字从大到小排序后得到a,从小到大排序得到b,然后用a-b替换原来这个数,并且继续操作。例如,从1234出发,依次可以得到4321-1234=3087、8730-378=8352、8532-2358=6174、7641-1467=6174,回到了它自己。

    输入一个n位数,输出操作序列,直到出现循环(即新得到的数曾经得到过)。输入保证在循环之前最多只会产生1000个整数。

    样例输入:1234

    样例输出:1234->3087->8352->6174->6174

代码:

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

int get_next(int x)
{
    int a,b,n;
    char s[10];
    sprintf(s,"%d",x);//字符串格式化命令,主要功能是把格式化的数据写入某个字符串中。sprintf 是个变参函数。
    n=strlen(s);
    for(int i=0;i<n;i++)
        for(int j=i+1;j<n;j++)
            if(s[i]>s[j])
            {
                char t=s[i];
                s[i]=s[j];
                s[j]=t;
            }
    sscanf(s,"%d",&b);//sscanf() - 从一个字符串中读进与指定格式相符的数据. 
    for(int i=0;i<n/2;i++)
    {
        char t=s[i];
        s[i]=s[n-1-i];
        s[n-1-i]=t;
    }
    sscanf(s,"%d",&a);
    return a-b;
}

int num[2000],count;
int main()
{
    scanf("%d",&num[0]);
    printf("%d",num[0]);
    count=1;
    for(;;)
    {
        num[count]=get_next(num[count-1]);
        printf("->%d",num[count]);
        int found=0;
        for(int i=0;i<count;i++)
            if(num[i]==num[count])
            {
                found=1;
                break;
            }
        if(found)
            break;
        count++;
    }
    printf("
");
    return 0;
}


5.3.2 字符重排

     输入一个字典(用******结尾),然后再输入若干单词。每输入一个单词w,你都需要在字典中找出所有可以用w的字母重排后得到的单词,并按照字典序从小到大的顺序在一行中输出(如果不存在,输出:()。输入单词之间用空格或空行隔开,且所有输入单词都由不超过6个小写字母组成。注意,字典中的单词不一定按字典序排序。

     样例输入:

     tarp given score refund only trap work earn course pepper part

     ******

     resco nfudre aptr sett oresuc

     样例输出:

     score

     refund

     part trap tarp

     :(

     course

代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int n;
char word[2000][10],sorted[2000][10];
//字符比较函数 
int cmp_char(const void* _a,const void* _b)
{
    char* a=(char*)_a;
    char* b=(char*)_b;
    return *a-*b;
}
//字符串比较函数 
int cmp_string(const void* _a,const void* _b)
{
    char* a=(char*)_a;
    char* b=(char*)_b;
    return strcmp(a,b);
}

int main()
{
    n=0;
    for(;;)
    {
        scanf("%s",word[n]);
        if(word[n][0]=='*')
           break;//遇到结束标志就终止循环 
        n++;
    }
    qsort(word,n,sizeof(word[0]),cmp_string);//给所有单词排序 
    for(int i=0;i<n;i++)
    {
        strcpy(sorted[i],word[i]);
        qsort(sorted[i],strlen(sorted[i]),sizeof(char),cmp_char);//给每个单词排序 
    }
    
    char s[10];
    while(scanf("%s",s)==1)//持续读取到文件结尾 
    {
        qsort(s,strlen(s),sizeof(char),cmp_char);//给输入单词排序 
        int found=0;
        for(int i=0;i<n;i++)
           if(strcmp(sorted[i],s)==0)
           {
               found=1;
               printf("%s",word[i]);//输出原始单词,而不是排序后的 
           }
        if(!found)
          printf(":(");
          printf("
");
    }
    return 0;
}

5.4.1 Cantor的数表

     如下列数,第一项是1/1,第二项是1/2,第三项是2/1,第四项是3/1,第五项是2/2,……。输入n,输出第n项。

    1/1   1/2  1/3  1/4  1/5

    2/1   2/2  2/3  2/4

    3/1   3/2  3/3

    4/1   4/2

    5/1

   样例输入:

   3

   14

   7

   12345

   样例输出:

   2/1

   2/4

   1/4

   59/99

分析:

      按照斜线分类,第一条斜线有一个数,第二条斜线有2个数……第i条有i个数。前i条斜线一共有S(k)=1+2+3+……+k=1/2*k*(k+1)个数。

     第k条斜线的倒数第i个元素是i/(k+1-i)。

代码:

//利用代数,避免浮点误差 
#include<stdio.h>
#include<math.h>
int main()
{
    int n;
    while(scanf("%d",&n)==1)
    {
        int k=(int)floor((sqrt(8.0*n+1)-1)/2-1e-9)+1;
        int s=k*(k+1)/2;
        printf("%d/%d
",s-n+1,k-s+n);
    }
    return 0;
}

5.4.2 因子和阶乘

    输入正整数n(2≤n≤100),把阶乘n!=1×2×3×……×n分解成素因子相乘的形式,从小到大输出各个素数(2、3、5……)的指数。

    例如825=3×52×11应表示成(0,1,2,0,1),表示分别有0、1、2、0、1个2、3、5、7、11.你的程序应忽略比最大素因子更大的素数(否则末尾会有无穷多个0)。

    样例输入:

    5

    53

    样例输出:

    5!= 3 1 1

    53! = 49 23 12 8 4 4 3 2 2 1 1 1 1 1 1 1

代码:

#include<stdio.h>
#include<string.h>
//素数判定,注意,n不能太大 
int is_prime(int n)
{
    for(int i=2;i*i<=n;i++)
       if(n%i==0)   return 0;
    return 1;
}
//素数表 
int prime[100],count=0;
int main()
{
    //n和各个素数的指数 
    int n,p[100];
    
    //构造素数表 
    for(int i=2;i<=100;i++)
       if(is_prime(i))
           prime[count++]=1;
    
    while(scanf("%d",&n)==1)
    {
        printf("%d!=",&n);
        memset(p,0,sizeof(p));
        int maxp=0;
        for(int i=1;i<=n;i++)
        {
            //必须把i复制到变量m中,而不要在做除法时直接修改它 
            int m=i;
            for(int j=0;j<count;j++)
                while(m%prime[j]==0)//反复除以prime[j],并累加p[j] 
                {
                    m/=prime[j];
                    p[j]++;
                    if(j>maxp)//更新更大素因子下标 
                       maxp=j;
                }
        }
        //只循环到最大下标 
        for(int i=0;i<=maxp;i++)
           printf("%d",p[i]);
        printf("
");
    }
    return 0;
}

5.4.3果园里的树

果园里的树排列成矩阵。它们的x,y坐标均是1~99的整数。输入若干个三角形,依次统计每一个三角形内部和边界上共有多少棵树

   样例输入:

   1.5 1.5        1.5 6.8        6.8 1.5

   10.7 6.9       8.5 1.5       14.5 1.5

   样例输出:

    15

    17

分析:

  此处用到了三角形的有向面积

代码:

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

double area2(double x0,double y0,double x1,double y1,double x2,double y2)
{
    return x0*y1+x2*y0+x1*y2-x2*y1-x0*y2-x1*y0;
}

int main()
{
    double x0,y0,x1,y1,x2,y2;
    while(~scanf("%lf %lf %lf %lf %lf %lf",&x0,&y0,&x1,&y1,&x2,&y2))
    {
        printf("%d
",(int)fabs(area2(x0,y0,x1,y1,x2,y2))/2+1);
    }
    return 0;
}                    
原文地址:https://www.cnblogs.com/lipching/p/3873212.html