程序设计题解

目录

  • Problem 01表达式的值为素数(筛法,预处理,函数)
  • Problem 02回文串(暴力循环)
  • Problem 03A的B次方(小心溢出)
  • Problem 04集合的减法(注意要排序)
  • Problem 05走楼梯(斐波那契数列)
  • Problem 06进制转化(注意大于十数值的表示)
  • Problem 07绝对值排序输出(按原数值输出呦)
  • Problem 08亲和数(求因子加和,注意1的存在)
  • Problem 09m个偶数的平均值(有可能有剩余)
  • Problem 10字符三角形(字符三角形与结束符无换行)
  • Problem 11末两位数(小于十的数前有0)
  • Problem 12坐过山车(二分图,匈牙利算法)
  • Problem 13和与积(负负得正,有可能是负数)
  • Problem 14龟兔赛跑(动态规划,最优解问题)
  • Problem 15手机短号(用字符串)
  • 总结

Problem 01

  • 题目描述

  表达式的值为素数给定范围和函数表达式的值,判断该值是否为素数,若范围内都为素数,输出“OK”,否则,输出“Sorry”

  • 思路

对所有范围内的数预处理,开一个标志数组,若值为素数则为1,否则为0。计算数值时,加一个标志变量,只要有一个数不是素数,就将标志变量赋值为0,跳出循环即可。

  • 细节

数据过大时,容易超时。对素数预处理循环到sqrti),节省时间,程序优化处理,加一个标志变量使程序更快进行。

注意多组输入,标志变量每一次都重新赋值。

  • 相似题目及处理方法
    相似问题还有完全平方数的处理,可以用预处理的方法,水仙花数也可以用这种方法。
    当然,判断素数除了预处理,也可以用函数来处理。
    int is_prime(int n)
    {
    int i;
        for(i=2;i<=sqrt(n);i++)
    {
    if(n%i==0)
    return 0;

            }

    return 1;

    }

   水仙花数预处理程序

for(i=100;i<1000;i++)

    {

        b=i%10,c=(i/10)%10,d=i/100;

        if(i==b*b*b+c*c*c+d*d*d)

        a[i]=1;

     }

  • 源程序

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

int a[11000];

int main()

{

    int i,j,x,y,flag=1,s=0;

    for(i=2;i<11000;i++)//对素数进行预处理

    {

        a[i]=1;

        for(j=2;j<=sqrt(i);j++)

        {

            if(i%j==0)

            a[i]=0;

        }

    }

    while(cin>>x>>y)

    {

        flag=1;

        if(x==0&&y==0)

        break;

        else

        {

            for(i=x;i<=y;i++)

            {

                s=i*i+i+41;

                if(!a[s])

                {

                    flag=0;//有一个不是素数就跳出循环

                    break;

                }

            }

            if(flag)

            cout<<"OK"<<endl;

            else   

            cout<<"Sorry"<<endl;

        }

    }

    return 0;

}  

 

 

Problem 02

  • 题目描述
    回文串,如“level”前后元素对称,输出“yes”,否则,输出“no”。
  • 思路
    暴力循环每一个元素。
  • 细节
    输入时输入的是每一个字符串,求每一个字符串的长度strlen函数,用标志变量记录有没有前后不同的字符。
    注意多组输入,标志变量每一次都重新赋值。
  • 其他方法,其他类似题

除了暴力,还可以从中间向两边扩展,以及动态规划,当然用这种方法求回文里最长子串的题目。当然,也可以通过递归的方法简化问题(回文串的子串也是回文,每次去掉两端字符,达到简化问题的目的)

回文串有很多题目,可以找一个最长的子串,也可以通过变化相邻两个字母将一个字符串从不是回文变为回文,统计输入字符串里有多少不重复的。

递归的实现

#include <iostream>

using namespace std;

int fun(int low, int high, char *str, int length)

{

        if (length == 0 || length == 1)

return 1;

if (str[low] != str[high])

return 0;

return fun(low+1, high-1, str, length-2);

}

int main()

{

char str[1000];

scanf(“%s”,str);

int length = strlen(str);

cout << fun(0, length-1, str, length) << endl;

return 0;

}

  • 源程序
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    char a[110];
    int main()
    {
        int n,i,flag,l;
        while(cin>>n)
        {
            while(n--)
            {
                flag=1;
                scanf("%s",a);//输入字符串
                l=strlen(a);//求字符串长度
                i=0;
                while(i<l-1)
                {
                    if(a[i]!=a[l-1])
                    {
    flag=0;//出现不成立的,就将标志变量赋值为0;并跳出循环
    break;
                    }
                    i++;
                    l--;
                }
                if(flag)
                cout<<"yes"<<endl;
                else
                cout<<"no"<<endl;  
            }
        }
            return 0;
    }
       

 

 

Problem 03

  • 题目描述
    A的B次方,给定两个数,求幂次值。
  • 思路
    循环B次,每次乘于A。
  • 细节
    指数型增长的数据值,最后肯定会溢出,因为只求后三位数,因此只需每次都将数据对1000求模即可。
    注意多组输入,定义的乘积每一次都重新赋值且为1。
    定义时用long long。
  • 其他方法

快幂算法(核心:二分法)

 int quickMod(int a, int b, int c)

{

int ans = 1;

while (b)

{

if (b % 2 == 1)//也可以写成if(b&0x1)

ans = (ans * a) % c;

b /= 2;//也可以写成b>>=1

a = (a * a) % c;

}

return ans;

}

  • 源程序
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int main()
    {
        long long int n,i,m,t;//定义64位整型数
        while(cin>>n>>m)
        {
            t=1;//每次赋初值为1
            if(!n&&!m)
            break;
            else
            {
                for(i=1;i<m;i++)
                {
                    t=t*n%1000;//每次对1000求模
                }
                cout<<t%1000<<endl;
            }
        }
        return 0;
    }

 

 

Problem 04

  • 题目描述
    集合的减法,两个集合的差值排序输出值,若为空集,输出“NULL”。
  • 思路
    用两个数组表示集合,如果集合A中的元素集合B中没有,则将元素赋给另一个数组储存,并将元素的个数通过累加和记录,最后排序输出,若累加和为0,则输出“NULL”。
  • 细节
    Sort函数有效区间为前闭后开,排序时后面写的是第一个无效数据。
    注意多组输入,累加和每一次都重新赋值且为0。
    两个集合作差,是两个集合的差集,而不是元素之间的减法。
  • 源程序
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int a[110],b[110],c[110];
    int main()
    {
        int i,x,y,j,k,sum;
        while(cin>>x>>y)
        {
            if(!x&&!y)
            break;
            else
            {
                for(i=0;i<x;i++)
                cin>>a[i];
                for(i=0;i<y;i++)
                cin>>b[i];
                k=0;
                for(i=0;i<x;i++)
               { 
                    sum=0;
                    for(j=0;j<y;j++ )
                    { 
                        if(a[i]==b[j])//判断两个集合的元素
                        sum++;
                    }
                    if(sum==0)
                    c[k++]=a[i];//数组储存两个集合的差值
                }
                if(k==0)    //两个集合差值为空,输出“NULL”
                cout<<"NULL";
                else       
                {
                    sort(c,c+k);//排序后输出
                    for(i=0;i<k-1;i++)
                    cout<<c[i]<<" ";
                    cout<<c[k-1];
                }
            }
            cout<<endl;
        }
    }

 

 

Problem 05

  • 题目描述

  有m阶楼梯,每次可以走一阶或两阶,求走的方式共有多少种。

  • 思路

两级有一种走法,三级有两种,四级可以通过先走两级再走两级,即两级和三级的方法之和,按照这个规律,第m阶是m-1m-2的方法之和,可以理解为斐波那契数列的应用。

  • 细节

注意数值的范围,斐波那契数列增长速度很快,容易造成溢出,大约到55左右。

用数组将所有的值计算并储存,用时调用即可,也是一种优化。

定义时用long long定义。

  • 相似题目及处理方法
    牛的数量,蜜蜂回蜂房的路线等都是斐波那契数列的变形。
    这个题也可以将走楼梯的方式改为一次走一级或三级,也为斐波那契数列的变形。
       牛的数量部分代码
    a[0]=1,a[1]=1,a[2]=2;
    for(i=3;i<60;i++)
        a[i]=a[i-1]+a[i-3];
       蜜蜂回蜂房部分代码
    cin>>a>>b;
    f=0;f1=1;

for(i=a;i<b;i++)

{

     f2=f+f1;

     f=f1;

     f1=f2;

     }

  • 源程序

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

int main()

{

    int m,n,i;

    cin>>n;

    int a[50];

    a[0]=1,a[1]=2;

    for(i=2;i<50;i++)//将所有的方法求出并用数组储存

    a[i]=a[i-1]+a[i-2];//斐波那契数列规律

    for(i=0;i<n;i++)

    {

        cin>>m;

        cout<<a[m-2]<<endl;

       

    }

    return 0;

}

 

 

Problem 06

  • 题目描述

  进制转化,将十进制数转化为R进制。

  • 思路

只要每次用十进制数对R求模,结果用数组储存,然后每次除以R,直至等于0

  • 细节

超过十进制数后,会出现用字符表示数的情况,比较容易出错,负数时输出负号。

可以通过ASCLL码有序性优化程序。

  • 相似题目及处理方法
    Sky的数(十进制数和十二进制数十六进制数)以及综合题中1的个数(其实就是2进制的转化)。
    Sky的数部分代码
    for(i=1;m>0;i++)       
            {           
                a[i]=m%10;           
                m/=10;           
                sum+=a[i];       
            }       
            for(i=1;k>0;i++)       
            {           
                b[i]=k%12;           
                k/=12;           
                s+=b[i];       
            }       
            for(i=1;x>0;i++)       
            {           
                c[i]=x%16;           
                x/=16;          
                t+=c[i];       
            } 
    1的个数部分代码
     for(;n!=0;n>>=1)
        {
            sum+=n&1;
        }    
  • 源程序

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

int main()

{

     long long int a,b,j;

     char n;

     while(cin>>a>>b)

     {

         long long int c[101],m=0;

         if(a<0)

         {

             a=-a;

             cout<<"-";

         }

         if(a==0)

         {

             cout<<a<<endl;

         }

         while(a>0)

         {

             c[m++]=a%b;//进制转化并用数组储存

             a=a/b;

         }

         for(j=m-1;j>=0;j--)

         {     

             if(c[j]>=10)

             {

                 n=c[j]+55;通过ASCLL码数值是有序的,简化程序

                 cout<<n;

             }

             else

             cout<<c[j];

         }

         cout<<endl;

    }

}

 

 

Problem 07

  • 题目描述

  绝对值排序输出,将数值按照绝对值排序,原数按照绝对值的顺序输出。

  • 思路

定义两个数组,一个储存原数,一个储存绝对值,对绝对值数组进行排序的同时,按照相同的方式,对原数组排序。

  • 细节

排序不能用sort函数,必须要保留排序的记录,可以用冒泡,选择,折半查找。

输出时注意最后一个元素不能有空格,两种输出方式,可以先输出第一个元素,其余先输出空格再输出数值,或者输出前n-1个数,每个数后加一个空格,最后输出第n个数。

  • 相似题目及处理方法
    Oj数组题中倒置排序和这个题可以用相同的方法,通过两个数组储存,计算出倒置数,排序。
    倒置排序部分代码
      for(i=0;i<n;i++)
        {
            t=a[i];a[i]=0;
            for(j=0;t>0;j++){
            a[i]=a[i]*10+t%10;
            t/=10;}
        }
        for(i=0;i<n;i++)
        for(j=i+1;j<n;j++)
        {
            if(a[i]>a[j]){
            c=a[i],a[i]=a[j],a[j]=c;
            d=b[i],b[i]=b[j],b[j]=d;}
        }  
  • 源程序

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

int a[110],b[110];

int main()

{

    int n,i,j,c,d;

    while(cin>>n)

    {

        if(n==0)break;

        else

        {

            for(i=0;i<n;i++)

            {

                cin>>a[i];

                if(a[i]<0)

                b[i]=-a[i];//将绝对值储存到新的数组里

                else

                b[i]=a[i];

            }

            for(i=0;i<n;i++){//冒泡对绝对值数组排序

            for(j=i+1;j<n;j++)

            {

                if(b[i]<b[j])

                {

                    c=a[i],a[i]=a[j],a[j]=c;//绝对值排序的同时,原数以相同的方式排序

                    d=b[i],b[i]=b[j],b[j]=d;

                }

            }}

            for(i=0;i<n-1;i++)

            cout<<a[i]<<" ";

            cout<<a[n-1]<<endl;//最后一个数分开输出

        }

    }

        return 0;

}

 

 

Problem 08

  • 题目描述

  亲和数,将两个数分解,所有因子的和相加等于另一个数即为亲和数,输出“YES”,否则,输出“NO”

  • 思路

求因子问题,可以理解为和素数问题相反,只要能整除就置为1,最后把数组内所有为1的相对应的循环变量累加起来和另一个数比较即可。

  • 细节
    1是每一个数的因子,求素数时从2开始,但求因子从1开始
    循环时循环变量到n/2即可,减少循环次数,因为因子除了本身其他值都小于n/2.
    因为是多组输入,标记数组和累加和每次都要重新赋值。
  • 其他做法

也可以用函数做,可以使程序更加简洁

int yinzihe(int y)

{

    b[1]=1;

for(j=2;j<=y/2;j++)

    if(y%j==0)

    b[j]=1;

    for(i=1;i<=y/2;i++)

    if(b[i])

    t+=i;

    return t;

}

  • 源程序

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

int a[610000],b[610000];

int main()

{

    int i,j,x,y,n,s=0,t=0;

    cin>>n;

    while(n--)

    {

        for(i=1;i<610000;i++)//每次循环重新赋值

        {

            a[i]=0;

            b[i]=0;

        }

        s=0,t=0;

        cin>>x>>y;

        a[1]=1,b[1]=1;//1是所有数的因子

        for(j=2;j<=x/2;j++)

        {

            if(x%j==0)

            a[j]=1;

        }

        for(i=1;i<=x/2;i++)

        {

            if(a[i])

            s+=i;

        }

        if(s==y)

        {

            for(j=2;j<=y/2;j++)

            if(y%j==0)

            b[j]=1;

            for(i=1;i<=y/2;i++)

            if(b[i])

            t+=i;

            if(t==x)

            cout<<"YES"<<endl;

            else

            cout<<"NO"<<endl;

        }

        else

        cout<<"NO"<<endl;

    }

}

 

 

Problem 09

  • 题目描述

  M个偶数的平均值,n个从2递增的偶数序列,m个数求一次平均值,如果不够,求剩余数平均值。

  • 思路

循环变量每次加2,外面的循环是n/m的数值,里面循环是m;每m个数求一次平均值,如果n不能整除m,最后输出n%m个数的值。

  • 细节

累加和每次内循环都要赋初值为0

输出时每个数之间有一个空格,最后一个数后没有空格,可以通过一个标志变量标记,如果是第一个数,输出该数值,改变标志变量的值,其余数先输出空格,再输出数值。  

  • 源程序

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

int main()

{

    int i,n,m,j,sum,x=0,flag=1;

    while(cin>>n>>m)

    {

        x=0;

        flag=1;

        for(i=1;i<=n/m;i++)//循环n/m

        {

            sum=0;

            for(j=1;j<=m;j++)//每m个数求一次平均值

            {

                x+=2;

                sum+=x;

            }

            if(flag)

            {

                cout<<sum/m;

                flag=0;

            }

            else

            cout<<" "<<sum/m;

        }

        sum=0;

        if(n%m)//如果剩下的数不够m,求剩余数的平均值

        {

            for(i=1;i<=n%m;i++)

            {

                x+=2;

                sum+=x;

            }

            cout<<" "<<sum/(n%m);

        }

        cout<<endl;    

    }

}

 

 

Problem 10

  • 题目描述

  字符三角形,输入n,输出高为n,底边为2n-1的空心字符三角形,输入@时结束。

  • 思路

三个边长处都输出字符,其余位置输出空格,控制好行和列数即可。

  • 细节

题目要求每两个三角形之间有一个换行,输出结束符@时没有换行,但是无法确定什么时候输出最后一个有效字符,因此可以加一个标志变量,如果是第一个图形,就只输出图形,其余的在前面输出换行。

  • 相似题目及处理方法
    oj中循环里的画矩形,蛋糕裱花,粘墙三角形等都相类似,通过找规律判断什么时候输出字符,什么时候输出空格即可。 
  • 源程序

 

    #include<iostream>

#include<cstdio>

using namespace std;

int main()

{

    char a;

    int b,j,i,flag=1;

    while(cin>>a)

    {

        if(a=='@') break;

        else

        {

            cin>>b;

            if(flag)

            flag=0;

            else

            cout<<endl;//除了第一个图形,其余图形先输出换行再输出图形

            for(i=1;i<=b;i++)

            {

                if(i==b)

                {

                    for(j=1;j<=2*b-1;j++) cout<<a;//最后一行没有空格

                }

                else

                {

                    for(j=1;j<=2*b-1;j++)

                    {

                        if(j==b+1-i||j==b+i-1) cout<<a;//三角形边缘输出字符

                        else if(j<b+i-1) cout<<" ";//三角形里面输出空格

                        else break;

                    }

                }

                cout<<endl;//每一行都要换行

            }

           

        }

    }

    return 0;

}

 

 

Problem 11

  • 题目描述

  末两位数,已知一位数是另一位数的倍数,已知这个数的前几位数,求这个数后两位所有可能的结果。

  • 思路

既然求两位数可能的结果,那么可以从0100暴力,只要满足题意输出即可。

  • 细节

既然是一个数的后两位,那么如果十位数是0,也必须输出,因此可以通过判断符合条件的数的大小来决定是否输出0

输出的每个结果之间有一个空格,最后一个数后面没有空格,可以通过标志变量。

  • 其他方法
    将每个数分离,分别对十求模,所得的结果直接输出即可。(分离这个数,也就是把这个数先用一个数据保存起来,先除以10,再用所得结果和原数分别对十求模输出即可)
     也可以用控制域宽和前导零的方法输出。
  • 源程序

 

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

int main()

{

    int n,i,m,flag=1;

    while(cin>>n>>m)

    {

        flag=1;

        if(!n&&!m)

        break;

        else

        {

            flag=1;

            for(i=0;i<100;i++)

            {

                if((n*100+i)%m==0)

                {

                    if((i/10==0)&&flag==1)//分情况讨论输不输出0和空格

                    {

                        cout<<0<<i;

                        flag=0;

                    }

                    else if((i/10==0)&&(!flag))

                    cout<<" "<<0<<i;

                    else if((i/10)&&flag==1)

                    {

                        cout<<i;

                        flag=0;

                    }

                    else if((i/10)&&!flag)

                    cout<<" "<<i;

                }

            }

            cout<<endl;

        }

    }

    return 0;

}

Problem 12

  • 题目描述

 坐过山车,给出搭配的对数,男生女生的个数,可能搭配的情况,求最多有多少搭配成可以去坐过山车 。

  • 思路

求最多有多少对,就是在已知的所有搭配中,尽可能多的让男女搭配。

可以这样理解,女生是一个点集,男生看做另一个点集,求最大匹配问题。也就是一个二分图的最大匹配问题。

  • 细节

找到一个搭配以后,累加和需要自加,但找最大匹配,有可能一开始的搭配不行,因此,当换另一种匹配时,要去找另一个女生的其他匹配方法。

  • 相似题目及处理方法
    可以用匈牙利算法,找最大匹配问题,也就是二分图,也就是递归寻找配对。
    寻找增广路的实现代码

 bool find(int x)

{

for (int j = 1;j <= n;j++)

{

if (arc[x][j]&& !v[j])

{

v[j]=1;

if (b[j]==0 || find(b[j]))

{

b[j] = x;

return true;

}

}

}

return false;

}

for (int i = 1; i <= m; i++)

{

memset(v,0,sizeof(v)); //注意每一次v都要清空,每一次找增广路都是一次新的开始

if (find(i)) ans += 1;

}

  • 源程序

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

int line[505][505],girl[505],flag[505]; //flag表示该男生是否被询问过

int n,m;

int find(int x) //为任意一个女生寻找最佳伴侣,找到则返回1

{

    for(int k=1;k<=n;k++)

if(line[x][k]==1&&flag[k]==0) //若两人之间有关系且在这次查找中没有被询问

    {

flag[k]=1; //标志该男生在此次查找中已被询问

if(girl[k]==0||find(girl[k])) //如果该男生没有女伴或者该男生的女伴可以找到其他男生,则匹配成功,这是一个递归过程

{  

girl[k]=x; //符合条件则将该女生和该男生匹配上,并标记

return 1;

}

 }

return 0;

}

int main()

{  

    int i, a,b,num, sum;   

    while (cin>>num)   

    {      

        if(!num)

        break;     

        cin>>m>>n;     

        memset(line,0,sizeof(line));

        memset(girl,0,sizeof(girl));

for(i=1;i<=num;i++)

{

 cin>>a>>b;

line[a][b]=1;  //表示女生a和男生b有关系

}

for(i=1;i<=m;i++) //逐个扫描每个女生,为她们寻找最佳伴侣

{

memset(flag,0,sizeof(flag)); //每次循环将标志都清零

if(find(i)) //如果找到,则最大匹配数加1

sum++;

}      

cout<<sum<<endl;   

    }  

    return 0;

}

Problem 13

  • 题目描述

  和与积,输入两个数,如果第一个数是两个数的和,第二个数是相应的两个数的乘积,则输出“Yes”,否则,输出“No”

  • 思路

加法可能会出现一个正数和一个负数,以此可以从乘法入手,转化成求一个数的因子问题,再将两个因子求和判断是否等于第一个数即可。

  • 细节

求因子时可以判断到开根时,也就是判断素数的变化,乘积为正时,也有可能是两个负数。

多组输入,标志变量和累加和每次重置。

  • 其他方法
    可以直接判断乘积的绝对值
       sum=0;
       for(j=1;j*j<=abs(b);j++)
       {
    if(b%j==0)
             {if(b/j+j==a||-(b/j+j)==a)
             { cout<<"Yes"<<endl;sum++;}}}
               if(sum==0)
               cout<<"No"<<endl;
    暴力查找
    for(int i=-10000;i<=10000;i++)
            {
                if(i*(n-i)==m)
                { flag=1;
                    cout<<"yes"<<endl;
                    break; }
            }
            if(flag==0)
            cout<<"no"<<endl; }
  • 源程序

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

int a[11000];

int main()

{   

    int i,x,y,flag=1,sum=0;   

    while(cin>>x>>y)   

    {       

        flag=1;       

        sum=0;       

        if(!x&&!y)       

        break;       

        else       

        {           

            if(y==0)           

            cout<<"Yes"<<endl;           

            else if(y<0)           

             {               

                 flag=0;               

                 y=-y;           

             }           

             for(i=1;i<=sqrt(y);i++)//先讨论乘积           

             {               

                  if(y%i==0) //找出因子后,分情况判断              

                  {                   

                        if(flag&&((i+y/i==x)||((-i)+(-y/i)==x)))                   

                        {                       

                            cout<<"Yes"<<endl;                       

                            sum++;                       

                            break;                  

                         }                   

                         else if((!flag)&&((i+(-y/i)==x)||((-i)+y/i==x)))                   

                         {                       

                                cout<<"Yes"<<endl;                      

                                sum++;                       

                                break;                  

                         }              

                     }          

               }          

               if(!sum)           

               cout<<"No"<<endl;       

        }   

    }

}

 

 

Problem 14

  • 题目描述

  龟兔赛跑,已知兔子是匀速,乌龟有电动车,路程中有若干个充电站,每次充电需要耗费一定的时间,充满电只能走一定的路程,没电时速度要慢,求谁先到达终点。

  • 思路

最优解问题:兔子的时间是一定的,题目转化为求乌龟所用的最短时间,也就是在总路程内判断电动车充几次电,判断在两个充电站之间,是充电所用时间短,还是不充电所用时间短,每一段都判断,选取最优方案。

  • 细节

多组输入,标志数组每次都要清零。

将始点和终点也看做有加油站,每次判断所用的最短时间,总时间每次都加上每一段的最短时间,最后所求即为最优解。

  • 相似题目及处理方法
    最优解问题用动态规划可以处理,虽然时间复杂度比较高,但在一定数的范围内,动态规划仍是一种好的方法。
    加油站问题,最少加几次油,可以到达终点。
  • 源程序

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

int path[102];

double dp[102];

int main()

{

int L,N,C,T,vr,vt1,vt2;

while(cin>>L)

{

cin>>N>>C>>T;

cin>>vr>>vt1>>vt2;

for(int i=1;i<=N;++i)

cin>>path[i];

path[0]=0;path[N+1]=L;//每个充电站看作一个节点,把起点和终点也看作节点

dp[0]=0;

for(int i=1;i<=N+1;i++)

{

double min=1000000;//从第J到第I个充电站的最短时间

for(int j=0;j<i;++j)

{  

double temp;//temp是指从起点到节点i所用的时间

if(path[i]-path[j]>=C)//从节点j到节点i的距离大于等于C的话

temp=dp[j]+C*1.0/vt1+(path[i]-path[j]-C)*1.0/vt2; //时间是起点到节点j加上从ji这一段所用的时间(分为两部分)

else

temp=dp[j]+(path[i]-path[j])*1.0/vt1;

if(j>0)

temp+=T;//在节点j充电的时间,计算的时候看作每次都是在节点j充满电再走向节点i

if(temp<min)

min=temp;//取最小时间

}

dp[i]=min;

}

double rt;

rt=L*1.0/vr;//兔子用的时间

if(dp[N+1]<rt)

cout<<"What a pity rabbit!"<<endl;

else

cout<<"Good job,rabbit!"<<endl;

}

return 0;

}

 problem 15

  • 题目描述

  手机短号,输入一个手机号,输出6和手机号后五位。

  • 思路

用数组将手机号储存起来,输出相应位置的值。

  • 细节

定义数组时,将手机号理解为字符串,因此定义时应该定义字符数组。

  • 相似题目及处理方法
    菜价总数,定义菜名时必须使用字符串,一个汉字占两个字节。汉字输入时,定义变量需要用字符串定义。 
  • 源程序

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

char a[20];//定义一个字符数组,也可以理解为定义一个字符串

int main()

{

    int n,i,j,k;

    cin>>n;

    for(i=1;i<=n;i++)

    {

        for(j=1;j<=11;j++)

        cin>>a[j];

        cout<<6;

        for(k=7;k<=11;k++)//输出后5

        cout<<a[k];

        cout<<endl;

    }

    return 0;

}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值