算法竞赛入门经典 第五章 基础题目选讲

5.1.1 WERTYU

虽然可以用if else或者switch进行这种变换,但是这样是非常麻烦的,会存在很多的分支,显得程序很臃肿。

一个优雅的解决方法是采用常量数组的方式。

#include<stdio.h>

char *s = "`1234567890-=qwertyuiop[]asdfghjkl;'\zxcvbnm,./"; // 常量数组能够很好解决按键位移问题
int main(){
    int i,c;
    while((c=getchar())!=EOF){
        for(i=1; s[i] && c!=s[i]; i++);
        if(s[i]) putchar(s[i-1]); // 如果是以上s字符串里面的字符,可以变成它的前一个
        else putchar(c); // 否则,空格等别的占位符,保持不变
    }
    return 0;
}

5.1.3 周期串问题

#include<stdio.h>
#include<string.h>
int main(){
    char word[100];
    scanf("%s",word); // %s要求的是一个地址,字符串的名字就是第一个字符的地址
    int len = strlen(word);
    for(int i=1; i<len; i++) // 第一个循环是确定循环节的大小
        if(len%i==0){ 
        int ok=1;
        for(int j=i; j<len; j++){ // 第二个循环是确保每个小节内容一致
            if(word[j]!=word[j%i]){ ok=0; break; }
        }
        // i是从小开始的递增的,因此只要找到第一个ok的周期就可以收工break了
        if(ok){ printf("%s",word); break; }
    }
}

5.2.1 小学生算术

#include<stdio.h>

int main(void) {
    int a, b;
    scanf("%d%d",&a,&b);
    if(!a && !b) return ;
    int c=0, ans=0;
    for(int i=9; i>=0; i--){ // 最高为九位,因此需要进行9次(除以10的)循环
        c=(a%10 + b%10 + c) > 9 ? 1 : 0; // c负责保存进位
        // 注意,当前位数a、b两者相加时还要考虑小一倍数的进位
        ans +=c; // 每次有进位就记入ans
        a/=10;
        b/=10;
        printf("%d",c);
    }
    printf("%d",ans);
}

5.2.2 阶乘的精确值

#include<stdio.h>
#include<string.h>
const int maxn = 3000;
int main(void) {
    int f[maxn]; // 定义数组,由于1000!约等于4*10^2567,因此数组可以取3000位
    int n, j, i;
    scanf("%d",&n);
    memset(f,0,sizeof(f)); // 将f从f[0]到f[2999]全部置零
    f[0]=1; // 对于n<2的那两个阶乘,结果均为1,这也是为什么i要从2开始
    for(i=2; i<=n; i++){
        int c=0;
        for(j=0; j<maxn; j++){ // 将f从f[0]到f[2999]每一位手动乘一遍i
            int s=f[j]*i+c; // 乘完得出来的数为s
            f[j] = s%10; // 取s的个位当作当前第j位的数字
            c = s/10; // s的十位作为大一位数的进位
        }
    }
    for(j=maxn-1; j>=0; j--) if(f[j]) break; // 从后往前数,直到第一个非零数字出现,也是乘积的最大位数
    for(i=j; i>=0; i--){ // 逆序表示,个位是f[0]、十位是f[1]……,方便进位,但是输出时要从后往前输出
        printf("%d",f[i]);
    }
    printf("\n");
}

 然后以下就是根据上面阶乘的原理用java做出来的大数乘法器:

import java.util.Scanner;
public class Main {
    // inspired by ‘5.2.2阶乘的精确值’ 的 乘法器
    public static void main(String[] args) {
        final int maxn=3000;
        int[] f = new int[maxn];
        int i, j, carry;
        
        Scanner s = new Scanner(System.in);
        String a = s.next();
        String b = s.next();
        // System.out.print("a="+a+", b="+b+"\n");

        int len_a = a.length();
        int len_b = b.length();

        // System.out.print("a.len="+len_a+", b.len="+len_b+"\n");

        // f全部置零
        for(int k=len_a-1; k>=0; k--){
            f[k] = 0;
        }
        
        //倒序,从低位(个位)开始计算,为了方便计算进位,将数组f的下标低位设置为结果的低位
        for(i=len_a-1; i>=0; i--){
            for(j=len_b-1; j>=0; j--){
                // 个位是0,十位是1...这样第i+j位就是两个当前被乘数的和所在的位置(乘法笔算)
                f[(len_a-i-1)+(len_b-j-1)]+=(a.charAt(i)-'0')*(b.charAt(j)-'0');
            }
        }
        
        // 把数组f中原先保留的数现在变成个位数,通过进位
        for(i=0; i<len_a+len_b-1; i++){
            carry = f[i]/10;
            f[i] = f[i]%10;
            f[i+1] += carry;
        }
        
        j=maxn-1;
        // for循环的作用仅仅是让j从后向前移动,消除首位零,直到第一个非零项
        for(; j>=0; j--) {
            if(f[j]!=0) {
                break;
            }
        }
        for(i=j; i>=0; i--){
            System.out.print(f[i]);
        } 
    }
}

这个大数乘法器能够实现超过2^31(Integer的尺寸)的数字的乘法

 

 

 

转载于:https://my.oschina.net/swanf/blog/3056254

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值