计算机程序设计实训记录(3)

解决完了例题后,就是10道oj题,挑一些我认为值得研究的题目记录一下吧

8 乘方计算
问题描述    给定一个unsigned long long型数据$x$,计算$x^2, x^3,\cdots$直到$x^5$或溢出为止。
输入    输入数据有若干行。每行上有一个unsigned long long型整数,对应一种情形。
输出    对于每一种情形,依次输出$x, x^2, x^3, x^4, x^5$的值,不输出计算溢出的数值。数据项之间用逗号、空格分隔。
输入样例
1111
11111
111111
输出样例
1111, 1234321, 1371330631, 1523548331041, 1692662195786551
11111, 123454321, 1371700960631, 15240969373571041
111111, 12345654321, 1371737997260631
【提示】在头文件climits(或limits.h)中宏定义了一些名称,用以表示一些数据类型取值的最大值。但不同的编译系统中宏定义的标识符为不尽一致。例如:有的用ULONG_LONG_MAX,而有的用ULLONG_MAX。可以采用如下办法在程序中统一使用ULONG_LONG_MAX。
#include  <limits.h>
#if
ndef  LONG_LONG_MAX
#define  LONG_LONG_MAX  LLONG_MAX
#define  ULONG_LONG_MAX  ULLONG_MAX
#endif

计算本身并不困难,难点在于如何判断溢出,直接比较大小显然是不可能的,因为在比较的时候就已经溢出了。

# include<stdio.h>
# include<math.h>
int main()
{
unsigned long long x,m,n; 
int i; 
while(scanf("%llu",&x)==1)
{ for(i=1;i<=5;i++)
    {
        m=powl(x,i);
        n=powl(x,i+1); 
        if(m<powl(x,(i-1)))
            break; 
        else if(m>n||i==5)
            printf("%llu\n",m); 
        else 
            printf("%llu, ",m);
    }
}
return 0;
}

 


 

 

11 兑换钱币
问题描述    对于给定的人民币金额n(分),问有多少种方案将其兑换成1分、2分、5分。
输入    输入数据有若干行。每行上有一个正整数表示以分为单位的人民币金额n,对应一种情形。
输出    对于每一种情形,输出结果、换行。
输入样例
10
100
150
输出样例
10
541
1186

这道题的解决思路不难想,直接使用穷举法是可以解决的。

#include<stdio.h>
int main()
{
    int a,b,c,n=1,i=0;
    double k=0;
    while(scanf("%d",&n)!=EOF){

        i++;
        for(a=0;a<=n/5;a++)
            for(b=0;b<=(n-5*a)/2;b++)//减去已经分配给5分的钱数
                for(c=0;c<=n-5*a-2*b;c++)//减去已经分给5分和2分的钱数
                {
                    if(c+2*b+5*a==n)
                        k++;
                }
                printf("%.0lf\n",k);
                k=0;
    }
    return 0;
}

 但是使用了三重循环来穷举会造成一个问题,就是运行时间过长,导致在学校OJ系统中TLE。

经过我们的观察不难发现,最后一次循环完全是多余的,只要配凑出5分和2分的数目,就可以解决这个问题。

#include<stdio.h>
int main()
{
    int a,b,c,n=1,i=0;
    double k=0;
    while(scanf("%d",&n)!=EOF){

        i++;
        for(a=0;a<=n/5;a++)
            for(b=0;b<=(n-5*a)/2;b++)//减去已经分配给5分的钱数
                {
                    if(2*b+5*a<=n)
                        k++;
                }
                printf("%.0lf\n",k);
                k=0;
    }
    return 0;
}

 而经过我优秀的同学们的讨论,也有不用穷举的办法。

因为确定了5分的钱数后,就只剩下2分和1分钱币的组合,而2分钱币可以转化为2个1分钱币,就是另一种组合

如假设共16分,在只有1个五分的情况下,就可以拆成

11=2+2+2+2+2+1

11=2+2+2+2+1+1+1

...

显然,11可以拆成5个2加1个1,就有5+1=6种组合

这样,这个问题就变成了在5分钱确定的情况下,求剩下可拆成最多几个2分钱的问题

#include<stdio.h>
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        int i,j,k,l=0;
        for(i=0; i<=n/5; i++)
        {
            k=(n-i*5)/2;
            l+=k+1;
        }
        printf("%d\n",l);
    }
    return 0;
}

 


 

13 指示灯控制
问题描述    有m(m<100)盏灯排成一排(从1到m按顺序依次编号)。灯的开关均为点触式的(即点一次开、再点一次则关)。现有n个人(从1到n依次编号)。第一个人(1号)将灯全部关闭。第二个人(2号)将所有2的倍数编号的灯的开关点一下。第三个人(3号)将所有3的倍数编号的灯的开关点一下。依此类推,当n个人完成其操作后,计算灯亮的数目。
输入    输入数据有若干行。每行上有两个非负整数对应一种情形的m和n。
输出    对于每一种情形,输出计算结果、换行。
输入样例
7 7
3 4
6 4
输出样例
5
2
2


非常有趣的题目,我自己的思路比较复杂。

首先,用一个数组来记录灯的开关情况,0为灭灯,1为亮灯,用一个函数来执行第n个人开关灯的过程,再用另一个函数来统计最后亮着的灯的数目。

开关灯的过程

int *light (int *num,int n,int m)
{
    int i;
    for(i=0;i<m;i++)
    {
        if((i+1)%n==0)
        {
            if(num[i])
                num[i]=0;
            else
            {
                num[i]=1;
            }
            
        }
    } 
    return num;
}

统计亮着的灯

int lcount(int *num,int m)
{
    int i,count=0;
    for(i=0;i<m;i++)
        if(num[i]==1)
            count++;
    return count;
}

 最后的完整代码,可以看到主函数里面还用了一个循环

#include <stdio.h>
int *light (int *num,int n,int m)
{
    int i;
    for(i=0;i<m;i++)
    {
        if((i+1)%n==0)
        {
            if(num[i])
                num[i]=0;
            else
            {
                num[i]=1;
            }
            
        }
    } 
    return num;
}
int lcount(int *num,int m)
{
    int i,count=0;
    for(i=0;i<m;i++)
        if(num[i]==1)
            count++;
    return count;
}
int main()
{
    static int num[100];
    int m,n,i,count;
    while(scanf("%d %d",&m,&n)!=EOF)
    {
        for(i=2;i<n+1;i++)
            light(num,i,m);
        count=lcount(num,m);
        printf("%d\n",count);
        for(i=0;i<100;i++)
            num[i]=0;
    }
    return 0;
}

 


 关于oj题就暂且告一段落,下面将会记录排序算法和字符串处理的内容。

posted @ 2020-08-02 00:29  DoRCL  阅读(444)  评论(0)    收藏  举报