《算法竞赛入门经典(第二版)》 紫书 各章课后习题答案及解析(持续更新)有疑问在评论区提问

序言

以下答案均是本人学习所得,重难点会有解析,仅供参考。

该文章旨在提供一个交流平台,大家可在评论区共同探讨问题。

若有疑问或者错误也可在评论区留言,周末统一回复。

制作不易,感谢支持!

第一章      1.5.3 习题

1-1 平均数(average)

#include <stdio.h>  
  
int main()  
{  
    int a, b, c;   
    scanf("%d %d %d", &a, &b, &c);   
    printf("%.3lf\n", (double)(a + b + c)/ 3.0); // 使用浮点数格式化输出  
    return 0;  
}

1-2 温度 (temperature)

# include <stdio.h>

int main()
{
    float f;
    scanf("%f", &f);
    printf("%.3f", 5*(f-32)/9);
    return 0;
}

1-3 连续和 (sum)

# include <stdio.h>

int main()
{
    int n;
    scanf("%d", &n);
    printf("%d", (1+n)*n/2);
    return 0;
}

1-4 正弦和余弦 (sin 和 cos)

  用到math.h库

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

int main()
{
    int a;
    const double pi = acos(-1.0);
    scanf("%d", &a);
    printf("%lf %lf", sin(a*pi/180), cos(a*pi/180));
    return 0;
}

1-5 打折 (discout)

# include <stdio.h>

int main()
{
    int num;
    scanf("%d", &num);
    if (num*95>=300)
    printf("%.2lf", (double)(num*95*0.85));
    else
    printf("%.2lf", (double)(num*95));
    return 0;
}

1-6 三角形 (triangle)

这个不太想写……有谁写了可以贴在评论区

1-7 年份(year)

# include <stdio.h>

int main()
{
    int year;//闰年的定义为能被四整除并且不能被一百整除,或者能被400整除
    printf("输入年份以判断闰年:" );
    scanf("%d", &year);  
    if ((year%4 == 0 &&year%100 !=0)||(year%400==0))
    {
        printf("%d年是闰年\n", year);
    }
    else
    {
        printf("该年不是闰年\n");
    }
    return 0;
}

  后面几个问题作者建议大家自己尝试,我也深有同感,直接贴出来感觉不太好……

  尝试过后有疑问直接在评论区问吧。

第二章

2-1 水仙花数(dafodil)

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

int main()
{
    for (int a=0;a<=9;a++)
    {
        for (int b=0;b<=9;b++)
        {
            int m = a*1100 + b*11;
            int n = floor(sqrt(m)+0.5);
            //floor will return an answer, which is not bigger than sqrt(m)
            if (n*n == m)
                printf("%d", m);
        }
    }
    return 0;
}

2-2 韩信点兵 (hanxin)

# include <stdio.h>
//# define LOCAL
int main()
{
    
    #ifdef LOCAL
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    #endif
    int x, y, z;
    int sum=0;
    while(scanf("%d %d %d", &x, &y, &z)==3)
        {
        sum++;
        int result = 0,check = 0;
        for(int i=10;i<=100;i++)
            {
                if ((i%3==x)&&(i%5==y)&&(i%7==z))
                {
                result = i;
                check = 1;
                }
            }
        if (check) printf("Case %d: %d\n", sum, result);
        else printf("No answer\n");
        }
    #ifdef LOCAL
    fclose(stdin);
    fclose(stdout);
    #endif
    
    return 0;
}

2-3 倒三角形 (triangle)

# include <stdio.h>

int main()
{
    int N;
    scanf("%d", &N);
    int j = N;
    for (int m=0;m<N;m++)
    {
        int i = 2*j-1;
        for (int q=0;q<m;q++)
        {
            printf(" ");
        }
        for (int p=0;p<i;p++)
        {
            printf("*");
        }
        printf("\n");
        j--;
    }
    return 0;
    
}

2-3 补充:

推荐大家做一个菱形的,题目如下:

已知一个整数n,你要根据n打印出n阶的实心菱形。

输入格式:

只有一个整数n(0<n<40,代表要打印的菱形阶数)。测试用例保证合法。

输出格式:

n阶实心菱形(占2乘n-1行)。

输入样例:

5

输出样例:

    *
   ***
  *****
 *******
*********
 *******
  *****
   ***
    *

2-4 子序列的和(subsequence)

# include <stdio.h>
//# define LOCAL

int main()
{
    # ifdef LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    # endif
    int n,m,pile;
    while (scanf("%d %d", &n,&m)==2)
    {
        if (n==0&&m==0) break;
        double sum = 0;
        while (n<=m)
        {
            sum += 1.0/n/n;
            n++;
        }
        pile ++;
        printf("Case %d: %.5lf\n", pile, sum);
    }
    # ifdef LOCAL
    fclose(stdin);
    fclose(stdout);
    # endif
    return 0;
}

2-5 分数化小数 (demical)

# include <stdio.h>
//# define LOCAL

int main()
{
    #ifdef LOCAL
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    #endif
    int a,b,c,sum=0;
    while (scanf("%d %d %d", &a, &b, &c)==3)
    {
        sum++;
        if (a==0&&b==0&&c==0) break;
        double m = (double)a/b;
        printf("Case %d:%.*lf", sum, c, m);
    }
    #ifdef LOCAL
        fclose(stdin);
        fclose(stdout);
    #endif
    return 0;
}

2-6 排列(permutation)

# include <stdio.h>

int check(int abc,int def,int ghi)
{
    int a=0, b=0, c=0, d=0, e=0, f=0, g=0, h=0, i=0;
    a = abc/100;b = (abc-a*100)/10;c = (abc-b*10-a*100);
    d = def/100;e = (def-d*100)/10;f = (def-e*10-d*100);
    g = ghi/100;h = (ghi-g*100)/10;i = (ghi-g*10-h*100);
    int arr[]={a, b, c, d, e, f, g, h, i};
    for (int i=0;i<=8;i++)
    {
        for(int j=i+1;j<=8;j++)
        {
            if (arr[i]==arr[j]) return 0;
        }
    }
}
int main()
{
    for (int i = 123;i <= 329; i++)
    {
        int checking = 1;
        int abc=0,def=0,ghi=0;
        abc = i;
        def = 2*abc;
        ghi = 3*abc;
        checking = check(abc, def, ghi);
        if (checking) printf("%d %d %d\n", abc,def,ghi);
    }
}

  老样子,问答题自己琢磨,动手尝试!!

第三章 

本章内容会有亿点点难,之后的题我会写一些关键的地方,譬如漏洞和易错点,也欢迎大家指出错误或者优化算法。

3-1 得分 (Score, UVa1585)

//2023.11.1

先给出题目输入输出:

题解点:sum += ++i;

注意:本题比较容易,但是如果样例过了OJ没过可以试试开一下O2优化,本题解就是开了O2优化才过的。

代码:

# include <stdio.h>
# include <string.h>
//# define LOCAL
# define maxn 85

int main()
{
    # ifdef LOCAL
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    # endif
    char arr[maxn];
    int n;
    scanf("%d", &n);
    while (n--)
    {
        int i=0;
        int sum=0;
        scanf("%s", arr);
        for (int j=0;j<maxn;j++)
        {
            if (arr[j]=='Y') break;
            else if (arr[j]=='X') 
            {
                i=0;
            }
            else if (arr[j]=='O')
            {
                sum += ++i;
            }
        }
        printf("%d\n", sum);
        memset(arr, 'Y', sizeof(arr));
    }
    # ifdef LOCAL
        fclose(stdin);
        fclose(stdout);
    # endif
    return 0;
}

3-2  分子量(Molar Mass, UVa1586)

//2023.11.2

输入输出:

分析:

1.声明两个常量(s和value)分别装CHON及其对应值。

2.也是题解点,就是要先判断元素符号后面是数字还是元素,若是数字那么究竟是一位还是两位数字。这个很关键,直接决定了你是否能做出来,读者也可以思考一下这问题。

代码:

# include <stdio.h>
//# include <string.h>
# define maxn 90
//# define LOCAL
const char* s="CHON";
const double value[]={12.01,1.008,16.00,14.01};
int main()
{
    # ifdef LOCAL
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    # endif
    char arr[maxn];
    int T;
    scanf("%d", &T);
    while (T--)
    {
        int num=1;
        double sum=0.0;
        int i=0;
        //memset(arr,'Z',sizeof(arr));
        int check = 0;
        scanf("%s", arr);
        for (i=0;i<maxn;i++)
        {
            num = 1;
            check = 0;
            if (arr[i]=='\0') break;
            if(arr[i+1]>='0'&&arr[i+1]<='9')
            {
                check = 1;
                if (arr[i+2]>='0'&&arr[i+2]<='9')
                {
                    check = 2;
                    num = (arr[i+1]-'0')*10+(arr[i+2]-'0');
                    //i = i+2;
                }
                else 
                {
                    num = arr[i+1]-'0';
                    //i = i+1;
                }
            }
            
            
                int LC=0;
                //char lett=arr[i];
                for (int j=0;j<4;j++)
                {
                    if (s[j]==arr[i]) 
                    {
                        LC=j;
                        break;
                    } 
                }
                sum += value[LC]*num;
            if (check!=0) 
            {
                i = i+check;
            }
        }
        printf("%.3lf\n", sum);
    }
    # ifdef LOCAL
        fclose(stdin);
        fclose(stdout);
    # endif
    return 0;
}

3-3 数数字 (Digit Counting)

简单题

心得:不要用计数器作其它用途!!

代码:

# include <stdio.h>
# include <math.h>
# include <string.h>
const int num[]={0,1,2,3,4,5,6,7,8,9};
int arr[10];

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        int n;
        int mid=0;
        scanf("%d", &n);
        for (int i=1;i<=n;i++)
        {
            mid = i;
            int len = (int)log10(mid)+1;
            for (int j=0;j<len;j++)
            {
                int temp = mid%10;
                for (int x=0;x<=9;x++)
                {
                    if (num[x]==temp)
                    {
                        arr[x] += 1;
                        break;
                    }
                }
                mid = mid/10;
            }
        }
        for (int y=0;y<=9;y++)
        {
            printf("%d", arr[y]);
            if (y!=9) printf(" ");
            else printf("\n");
        }
        memset(arr,0,sizeof(arr));
    }
    return 0;
}

3-4 周期串(Periodic Strings,UVa455)

//2023.11.6

本题有坑,本题有坑,本题有坑!

输入输出:

分析:

1.注意,这里的输入是每行间还有空行,所以我们需要用getchar()将空行读取('\n')。

2.输出也要有空行,但是最后一行不能多空,所以开头whlie(T--)读取行数,最后if (T) printd("\n")判断最后一行。

3.题解点:思考循环要怎么做到判断字符是否不重复,还要注意周期为1时的特殊情况。

代码:

# include <stdio.h>  
# include <string.h>  
# define maxn 85  
//# define LOCAL  
  
int main()  
{  
    # ifdef LOCAL  
        freopen("in.txt", "r", stdin);  
        freopen("out.txt", "w", stdout);  
    # endif  
    char a[maxn];
    int T;
    int ok=0;
    scanf("%d", &T);  
    while (T--)  
    {  
        getchar();
        scanf("%s", a);
        int len = strlen(a);
        int sum=0; 
        for (int k=1;k<=len;k++)
        {
            if (len%k==0)
            {
            for (int i=k;i<len;i++)
            {
                ok = 1;
                if (a[i]=='\0') 
                    break;
                
                if (a[i] != a[i%k])
                {
                    ok = 0;
                    break;
                }
                
            }
            if (ok)
                {
                    printf("%d\n", k);
                    break;
                }
            }
        }
        if (!ok)
        {
            printf("%d\n", len);
        }
        if (T) printf("\n");
    }  
    # ifdef LOCAL  
        fclose(stdin);  
        fclose(stdout);  
    # endif  
    return 0;  
}

3-5 谜题(Puzzle, UVa227)

//2023.11.6

本题含金量很高

分析:

1.想要读取网格数据就可以联想到二维数组,这里,我们使用二维数组读取字符。(不知道二维数组的同学可以参考此前例题“蛇形数”)

2.本题的含金量高体现在你如何处理多余字符,例如换行符‘\n’,这一点非常重要。这里使用getchar()处理。

3.如何处理最后一行?笔者一开始就是因为没有处理好最后一行的空行结果PE了(也就是所谓的Presentation Error)

4.很坑的一点也是国内很多翻译没有翻译明白的一句话(或者压根就没有翻译)这里贴上英文原句:

意思就是说移动的输入可能会有很多行,所以一定是输入0后才结尾。嗯?感觉没看懂??看看输入:你大概就可以理解了。

所以这里又回到了第2点:处理换行符的问题。

5.题解点:不同数组间的交换问题。不过,老实说,题解点在这么多的坑中间感觉有些黯然失色了。

输入输出:

代码:

# include <stdio.h>
//# define LOCAL

int check(int a,int b)
{
    if ((a<0||a>4)||(b<0||b>4))
        return 1;
    else 
        return 0;
}
int main()
{
    # ifdef LOCAL
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    # endif
    char a[5][5];
    char b[100];
    int ok=0;
    for (int sum=1;;sum++)
    {
        int x=0,y=0;
        int cc=0;
        if (sum>1) getchar(); 
        for (int i=0;i<5;i++)
        {
            for (int j=0;j<5;j++)
            {
                scanf("%c", &a[i][j]);
                if (a[i][j]==' ')
                {
                    x=i;y=j;
                }
                if (a[i][j]=='Z')
                {
                    ok = 1;
                    break;
                }
                if (j==4) getchar();
            }
            if (ok) break;
        }
        if (ok) break;
        else 
        {
            if (sum>1) printf("\n");
        }
        for (int n=0;;n++)
        {
            scanf("%c", &b[n]);
            if (b[n]=='\n')
            {
                n--;
            }
            if (b[n]=='0') break;
        }
        for (int m=0;;m++)
        {
            if (b[m]=='0') break;
            if (b[m]=='A') 
            {
                if (check(x-1,y)) 
                {
                    cc=1;
                    break;
                }
                a[x][y]=a[x-1][y];
                a[x-1][y]=' ';
                x=x-1;
            }
            if (b[m]=='B') 
            {
                if (check(x+1,y)) 
                {
                    cc=1;
                    break;
                }
                a[x][y]=a[x+1][y];
                a[x+1][y]=' ';
                x=x+1;
            }
            if (b[m]=='L') 
            {
                if (check(x,y-1)) 
                {
                    cc=1;
                    break;
                }
                a[x][y]=a[x][y-1];
                a[x][y-1]=' ';
                y=y-1;
            }
            if (b[m]=='R') 
            {
                if (check(x,y+1)) 
                {
                    cc=1;
                    break;
                }
                a[x][y]=a[x][y+1];
                a[x][y+1]=' ';
                y=y+1;
            }
            if (cc) break;

        }
        
            printf("Puzzle #%d:\n", sum);
            if (cc)
            {
                printf("This puzzle has no final configuration.\n");
            }
            else
            {
                for (int i=0;i<5;i++)
                {
                    for (int j=0;j<5;j++)
                    {
                        printf("%c", a[i][j]);
                        if (j!=4) printf(" ");
                    }
                    printf("\n");
                }
            }
            //printf("\n");
    }
    # ifdef LOCAL
        fclose(stdin);
        fclose(stdout);
    # endif
}

3-6 纵横字谜的答案(Crossword Answers, UVa232)

//2023.11.8

心得:本题困了我很久,样例过了但是一直一直WA,以为是输出错一直在调输出格式,(虽然本题输出也有坑),结果发现是只是过了特例,少了一个else,警示警示! 

但是,笔者并没有因为为WA了25次(可能在比赛里已经凉了)就放弃,昨天debug快一点后,睡了六个小时爬起来继续,终于在今天早上AC了。所以我觉得这是我虽然没什么天赋却还在坚持学习的动力吧。

分析:

1.题解点1:白色空行的标记数字,哪些要标记,哪些不要。这里使用另一个数组来标记。(笔者也是这里WA了,主要是x和y>0时当上下都有*时,两个都会+数字,故重复)

2.题解点2:横向输出其实还行,需要考虑*和是否是第一行。还有换行符的使用也要仔细考虑。竖向输出是一个难点,这里在两个横竖循环的里面再加一层循环,在该循环中,判断是*或者最后一行或者是已经读取过的数字则跳过,这样就可以解决问题。

3.其它:和上题一样,本题也有\n,所以要有getchar()的处理。还有数组要开大一点,规定的是10*10,那就开成12*12,防止下标溢出等问题(或许不是这个名词?)

4.其它的其它:本来这一点是我最想吐槽的,就是输出问题,开头我也说到我以为WA是因为格式错,可见本题的格式是多么……具体表现在:字母前的数字要占三格且靠右,所以要使用%3d解决。每一个谜题之间要有一个空行(这点也和上题差不多)这里在循环开头处理一下。

5.所见所想可能非所得。结合笔者的经历,知道了自己调试的点可能不是真正错误的地方,样例过了也许并不正确。所以需要自己细心再细心,多方面尝试才是可行之道。

输入:

输出:(英文原句好像有点误导,这里贴上笔者AC代码的输出)

代码:

# include <stdio.h>
# include <string.h>
//# define LOCAL
char arr[12][12];
int brr[12][12];
int main()
{
    # ifdef LOCAL
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    # endif
    
    int a,b;
    for (int i=1;;i++)
    {
        scanf("%d %d", &a, &b);
        if (a==0) 
        {
            break;
        }
        else
        if (i>1) printf("\n");
        //getchar();
        
        int sum=1;
        memset(brr,0,sizeof(brr));
        //memset(arr,,sizeof(arr));
        for (int x=0;x<a;x++)
        {
            for (int y=0;y<b;y++)
            {
                if (y==0) 
                    getchar();
                scanf("%c", &arr[x][y]);
                if (arr[x][y]=='*') 
                    brr[x][y]=-1;
                else if ((x==0&&arr[x][y]!='*')||(y==0&&arr[x][y]!='*')) 
                {
                    brr[x][y]=sum;
                    sum++;
                }
                else if (x>0||y>0)
                {
                    if (x>0&&arr[x-1][y]=='*')
                    {
                        brr[x][y]=sum;
                        sum++;
                    }
                    else if (y>0&&arr[x][y-1]=='*')
                    {
                        brr[x][y]=sum;
                        sum++;
                    }
                }
            }
        }
        printf("puzzle #%d:\n", i);
        printf("Across\n");
        for (int x=0;x<a;x++)
        {
            for (int y=0;y<b;y++)
            {
                if (arr[x][y]=='*')
                {
                    ;
                }
                else
                {
                    if (y==0)
                    {
                        printf("%3d.", brr[x][y]);
                    }
                    else if (arr[x][y-1]=='*')
                    {
                        printf("%3d.", brr[x][y]);
                    }
                    printf("%c", arr[x][y]);
                    if (y==b-1) 
                    printf("\n");
                    else if(arr[x][y+1]=='*')
                    printf("\n");
                }
            }
        }
        printf("Down\n");
        for (int x=0;x<a;x++)
        {
            for (int y=0;y<b;y++)
            {
                int sum=0;
                for (int m=x;m<a;m++)
                {
                    if (brr[m][y]==-1||brr[m][y]==-2) break;
                    if (sum==0)
                    {
                        printf("%3d.", brr[m][y]);
                    }
                    printf("%c", arr[m][y]);
                    brr[m][y]=-2;
                    sum++;
                    if (m==a-1)
                    printf("\n");
                    else if(brr[m+1][y]==-1)
                    printf("\n");
                }
            }
        }
    }
    # ifdef LOCAL
        fclose(stdin);
        fclose(stdout);
    # endif
    return 0;
}

3-7 DNA序列 (DNA Consensus String, UVa1368)

//2023.11.6

注意:本题使用贪心算法。

贪心算法:

1.将问题分为为若干个子问题。

 2.对每个子问题进行求解,得到子问题的局部最优解。

3.合成局部最优解得到答案。

看似很简单的理论却让我恍然大悟,如果还没有感觉就接着往下看。

分析:

1.刚看到问题(特别是英文原题)你可能会像笔者一样懵逼,然后开始想象一些特别复杂的解法……但是,当你知道有一种算法叫做贪心算法后,你可能就会茅塞顿开,恍然大悟。

2.题解点注意贪心算法的第1点,要分为若干个子问题,那么本题可以分的最小子问题是什么?稍微思考就得到:分为每一列对应的第一个字母(碱基名称)。然后从第2点,我们只需找到每一列数目最多的字母就可以使所谓的Hamming值最小。

3.上一点提供了基本思路,你大可以先尝试过后再接着看这一点。这一点主要讲解一些“坑”。首先,如果一列四个字母出现的字母都相同,我们应该储存哪一个呢?这里就要看看英文原题的要求:

简单来说就是要求返回数组的最小值。是的数组也是有大小的,如果你有认真做例题的话肯定知道。不知道也没关系,总之就是(字符)数组的ASCII码最小时,数组的值最小。这里直接比较每一行的大小然后返回那个最小的就行(A<C<G<T)。其次,你可能需要用到string.h库里的memset(re,'\0,sizeof(re))函数将循环里输出的数组清零。再次……你自行补充吧或者评论区见,有的坑比如’\n'的消除之前已经讲过了。

代码:

# include <stdio.h>
# include <string.h>
//# define LOCAL
char a[55][1010],b[55][1010],re[1010];
int main()
{
    # ifdef LOCAL
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    # endif
    int X;
    scanf("%d", &X);
    getchar();
    while(X--)
    {
        int m,n;
        
        int sum=0;
        int num = 0;
        int max = 0;
        scanf("%d %d", &m, &n);
        //getchar();
        for (int i=0;i<m;i++)
        {
            getchar();
            for (int j=0;j<n;j++)
            {
                scanf("%c", &a[i][j]);
            }
        }
        for (int j=0;j<n;j++)
        {
            int sum_A=0,sum_T=0,sum_C=0,sum_G=0;
            for (int i=0;i<m;i++)
            {
                if (a[i][j]=='A') 
                    sum_A++;
                if (a[i][j]=='T') 
                    sum_T++;
                if (a[i][j]=='C') 
                    sum_C++;
                if (a[i][j]=='G') 
                    sum_G++;
            }
            //sum = sum_A+sum_T+sum_C+sum_G;
            max = ((sum_A>=sum_C?sum_A:sum_C)>=(sum_G>=sum_T?sum_G:sum_T))?(sum_A>=sum_C?sum_A:sum_C):(sum_G>=sum_T?sum_G:sum_T);
            if (max==sum_A) re[num] = 'A';
            else if (max==sum_C) re[num] = 'C';
            else if (max==sum_G) re[num] = 'G';
            else if (max==sum_T) re[num] = 'T';
            num++;
            sum += max;
        }
        printf("%s\n", re);
        printf("%d\n", m*n - sum);
        memset(re, '\0',sizeof(re));
    }
    # ifdef LOCAL
        fclose(stdin);
        fclose(stdout);
    # endif
    return 0;
}

3-8 循环小数(Repeating Decimals,UVa202)

//2023.11.27 好久没更新哈

分析

1.本题要求找到分数的小数位数或者循环节,通过查阅发现double类型通常有 10 到 15 位有效数字,与本题的最多3000位小数有很大差距(后面会详细讲解为什么是3000位小数),所以考虑使用模拟除法

模拟除法:

回想一下初中或者小学我们是如何学习除法的:两数相除得到余数然后再将余数除以除数……直到余数为0或者循环。

所以我们可以运用同样的思路获得两数相除的小数位数。

具体方法是:初始化两个数组a,b,第0次:两数相除,a[0]保存商,b[0]保存余数,第1次循环,将b[0]*10/除数的商用a[1]保存,余数用b[1]保存……

现在,你应该理解了这个方法的精髓,就是最简单的除法运算,*10的目的是让得到的商和余数是整数用数组储存,每次都*10对应每次运算位数都增加1(仔细琢磨一下)。

2.不论循环或者不循环(那么循环节就是0,长度为1),我们都需要找到循环节。这里提供一个很重要的思想就是当模拟除法得到余数与之前有相等的情况时,那么将从下一次运算开始循环。这一点很好理解,这里不再赘述。所以,我们的目标就变成了寻找相同余数,而且一定会有(包括0)。

3.这一点就是喜闻乐见的卡输出环节了,这里原题(包括英文版)根本就没有好好讲输出要求。先贴上AC代码的输出:

可以发现第二行距离前面有3行空格,用%3d解决,然后就是省略号其实是...(三个英文句号),我现在都不懂自己怎么输入的半个中文省略号进去……(表示无语)。最后是空行,这里题目不懂为什么一改往日(其实这是远古题)要求的不要最后一行,这里你只需要输出两个\n就完事了。

小数化分数的位数

分数化为小数一定是有限或者有限循环

如何证明或者理解?

例如:p/q

仔细思考一下,使用模拟除法(或者最简单的除法),余数是一定小于除数的是吧?说明余数一定是有限的吧?既然余数有限而且小于除数q,那么是不是可以得出结论:最多运算q-1次,余数一定会重复。一旦余数重复,那么就开始循环。(仔细理解,笔者数学思维一般所以想了特别久才得出这个推导)

而且题目规定被除数和除数属于[0,3000],所以严谨来说,小数位数不会超过2999(实际上更少,但是不需要再挑战你的大脑!)

所以两个数组的大小也就确定了。

好了,废话有点多,上代码吧。

代码

# include <stdio.h>
# define maxn 3010
//# define LOCAL
int a[maxn], b[maxn];
int main()
{
    # ifdef LOCAL
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    # endif
    int m,n;
    //int sum=0;
    while (scanf("%d %d", &m, &n)==2)
    {
        /*if (sum!=0)
        {
            printf("\n");
        }*/
        
        int check = 0;
        int len = 0;
        int first = 0;//final = 49;
        a[0] = m/n;
        b[0] = m%n;
        for (int i=1;i<=3000;i++)
        {
            a[i] = b[i-1]*10/n;
            b[i] = b[i-1]*10%n;
            for (int j=0;j<i;j++)
            {
                if (b[j]==b[i])
                {
                    len = i-j;
                    first = j;//final = i;
                    check = 1;
                    break;
                }
            }
            if (check) break;
        }
        printf("%d/%d = %d.", m, n, a[0]);
        
        if (len>=50)
        {
            printf("(");
            for (int x=1;x<=50;x++)
                {
                    printf("%d", a[x]);
                }
            printf("...)");
        }
        else
        {
            for (int y=1;y<=first;y++)
                {
                    printf("%d", a[y]);
                }
        printf("(");
            for (int x=first+1;x<=first+len;x++)
                {
                    printf("%d", a[x]);
                }
        printf(")");
        }
        printf("\n");
        
        printf("   %d = number of digits in repeating cycle\n", len);
        printf("\n");
        //sum++;
    }
    # ifdef LOCAL
        fclose(stdin);
        fclose(stdout);
    # endif
    return 0;
}

3-9 子序列(All In All,UVa10340)

//24.1.21

好久好久没有更新,趁着寒假一口气更新完吧!(说大话……)

前言

本题好像是有什么特殊的题型,可以用特殊的体系解决,但众所周知,我是个懒汉,直接上手写了,也没有查资料,但是最后还是过了。

所以本篇题解可能没有什么知识内涵,算是一个其他大佬题解的补充吧!

分析

1.本题比较特殊的是题目中“删掉”这个词,也就是右字符串能按顺序一个一个删掉左字符串的内容。

由此得出“子序列“的要求就是按顺序存在即可。

2.本题输入要求读取到EOF截至意思就是一直读取到文件结尾。可以用scanf("%s", a)!=EOF来控制,具体操作可以看代码。

3.还有一个疑点就是本题没有要求字符串长度,所以当笔者一开始开了较小的数组区间结果返回RE(Runtime Error 运行时错误),得到这个错误大概率时数组没开够导致的访问越界,所以索性开到很大1048576(我不懂是不是最大,但肯定足够了)

4.最关键的是check函数部分,首先我在循环外定义了i和j,i用来代表左字符串的循环次数,j代表右字符串的循环次数,然后让左字符串的,每个值去对应右字符串的(这句话没看懂没关系,直接看代码会更直观),如果对应上了就让che自增,最后判断che是否和len_a相等……哎呀,感觉说的多了。

好了,话不多说,上代码。

代码

# include <stdio.h>
# include <string.h>
//# define LOCAL
# define maxn 1048576

int check(char a[], char b[])
{
    int len_a = strlen(a);
    int len_b = strlen(b);
    int che=0;
    int i=0,j=0;
    for (i;i<len_a;i++)
    {
        for (j;j<len_b;j++)
        {
            if (a[i]==b[j])
            {
                che++;
                j++;
                break;
            }
        }
    }   
    if (che==len_a)
        return 1;
    else 
        return 0;     
}
int main()
{
    # ifdef LOCAL
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    # endif
    char a[maxn],b[maxn];
    while (scanf("%s", a)!=EOF)
    {
        scanf("%s", b);
        int bin = check(a,b);
        if (bin)
            printf("Yes\n");
        else 
            printf("No\n");
    }
    return 0;
    # ifdef LOCAL
        fclose(stdin);
        fclose(stdout);
    # endif
}

未完待续……(主要我懒,明天更新)

Adios

  • 11
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值